Skip to content

Add TEXTBEFORE, TEXTAFTER and TEXTSPLIT functions - #1792

Open
marcin-kordas-hoc wants to merge 7 commits into
developfrom
feat/hf-text-splitting
Open

marcin-kordas-hoc wants to merge 7 commits into
developfrom
feat/hf-text-splitting

Conversation

@marcin-kordas-hoc

@marcin-kordas-hoc marcin-kordas-hoc commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds three functions: TEXTBEFORE, TEXTAFTER and TEXTSPLIT (HF-465, HF-466, HF-467).

  • TEXTBEFORE(text, delimiter, [instance_num], [match_mode], [match_end], [if_not_found]) returns the text before the nth occurrence of delimiter; TEXTAFTER returns the text after it. A negative instance_num counts from the end, match_mode 1 ignores case, match_end 1 treats the end of the text as a delimiter, and if_not_found replaces #N/A.
  • TEXTSPLIT(text, col_delimiter, [row_delimiter], [ignore_empty], [match_mode], [pad_with]) splits text into a two-dimensional array. It is an array function and follows the existing array-function conventions (size prediction and spilling).
  • All three live in TextPlugin, with metadata catalogue entries, translations for all built-in languages (English names kept, as no localized names were confirmed) and a CHANGELOG entry. No shared code is changed.

Behaviour check against Excel

98 formulas were evaluated in Excel Online (MS Graph live session) and in HyperFormula: 93 identical, 5 different. The 5 differences are explained and none points at a defect of these functions:

  • 4 come from the locale of the account used for measuring (Polish): Excel converts the number 1.5 to the text 1,5 and TRUE to PRAWDA before searching, so TEXTBEFORE(1.5,".") is #N/A in that Excel while TEXTBEFORE(1.5,",") is 1 (measured). HyperFormula converts to 1.5 and TRUE.
  • 1 is INDEX past the end of an array: Excel #REF!, HyperFormula #NUM!. That is the general INDEX behaviour, not specific to TEXTSPLIT.

TEXTSPLIT results were compared through ROWS, COLUMNS and INDEX probes (dimensions and individual elements), not by reading the spilled range. Inline array constants as delimiters ({",",";"}) could not be sent to Excel through the Graph API, so that form is covered by tests but not measured.

Known differences from Excel

Both are recorded in docs/guide/list-of-differences.md:

  • When ignore_empty is on and nothing is left after splitting (=TEXTSPLIT(",,", ",", , TRUE)), Excel returns #CALC! and HyperFormula #N/A, because HyperFormula has no #CALC! error.
  • The size of the spilled result depends on the text and the delimiters, and HyperFormula predicts it only when the text, the delimiters, ignore_empty and match_mode are literals (a number may carry a sign). With anything else, such as =TEXTSPLIT(1+1, ""), the formula is treated as one value and a longer result is #VALUE!. This is the same limitation as SEQUENCE with non-literal dimensions (=SEQUENCE(1+1) is #VALUE! today). Inside another function, for example =INDEX(TEXTSPLIT(A1, ","), 1, 2), any argument works. Cursor Bugbot raised this; the sign case is fixed and the rest is documented rather than changed, since fixing it for all array functions is a separate piece of work.

Tests

Paired tests branch: feat/hf-text-splitting in the tests repository (3 spec files, 211 tests). Full local run: 505 suites, 6445 passed, 3 skipped. Patch coverage of the new lines in TextPlugin.ts is complete except two defensive branches.

🤖 Generated with Claude Code


Note

Low Risk
New optional text functions in an isolated plugin with documented Excel deltas; no changes to core evaluation or licensing beyond registering the new names.

Overview
Adds Excel-style text functions TEXTBEFORE, TEXTAFTER, and TEXTSPLIT in TextPlugin, with shared delimiter matching (multi-delimiter, nth occurrence from either end, case sensitivity, optional end-of-text boundary, custom if_not_found).

TEXTSPLIT returns a spilled 2D array (row/column delimiters, ignore_empty, padding) and uses textsplitArraySize so spill dimensions are known only when text, delimiters, ignore_empty, and match_mode are literals—same pattern as SEQUENCE with non-literal sizes.

Wiring updates: function metadata, license capability list, CHANGELOG, i18n entries (English names), and list-of-differences.md notes (#N/A instead of Excel’s #CALC! when ignore-empty leaves nothing; literal-only spill sizing).

Reviewed by Cursor Bugbot for commit d8d10f5. Bugbot is set up for automated code reviews on this repo. Configure here.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
hyperformula-docs d8d10f5 Commit Preview URL

Branch Preview URL
Oct 08 2026, 04:29 AM

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/interpreter/plugin/TextPlugin.ts
@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Performance comparison of head (d8d10f5) vs base (3a9c34b)

                                     testName |    base |    head | change
--------------------------------------------------------------------------
                                      Sheet A |   502.6 |  485.56 | -3.39%
                                      Sheet B |  162.46 |  158.71 | -2.31%
                                      Sheet T |  139.26 |  137.44 | -1.31%
                                Column ranges |  522.31 |  517.06 | -1.01%
                                Sorted lookup | 14773.4 | 14787.9 | +0.10%
Sheet A:  change value, add/remove row/column |   15.12 |   15.61 | +3.24%
 Sheet B: change value, add/remove row/column |  130.72 |  137.55 | +5.22%
                   Column ranges - add column |  155.97 |  157.51 | +0.99%
                Column ranges - without batch |  479.09 |  492.53 | +2.81%
                        Column ranges - batch |  123.57 |  126.71 | +2.54%

marcin-kordas-hoc and others added 5 commits October 8, 2026 03:45
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A number literal with a sign is parsed as a unary operator, so the result size of
=TEXTSPLIT(-12.5, ".") was not predicted and the formula returned #VALUE!. The two remaining
differences from Excel (#N/A instead of #CALC!, literal arguments needed for sizing) are documented.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…y table

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/interpreter/plugin/TextPlugin.ts
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d8d10f5. Configure here.

Comment thread src/interpreter/plugin/TextPlugin.ts
@codecov

codecov Bot commented Oct 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.30%. Comparing base (3a9c34b) to head (d8d10f5).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1792      +/-   ##
===========================================
+ Coverage    97.26%   97.30%   +0.04%     
===========================================
  Files          203      203              
  Lines        16022    16188     +166     
  Branches      3555     3612      +57     
===========================================
+ Hits         15583    15751     +168     
+ Misses         431      429       -2     
  Partials         8        8              
Files with missing lines Coverage Δ
src/i18n/languages/csCZ.ts 100.00% <ø> (ø)
src/i18n/languages/daDK.ts 100.00% <ø> (ø)
src/i18n/languages/deDE.ts 100.00% <ø> (ø)
src/i18n/languages/enGB.ts 100.00% <ø> (ø)
src/i18n/languages/esES.ts 100.00% <ø> (ø)
src/i18n/languages/fiFI.ts 100.00% <ø> (ø)
src/i18n/languages/frFR.ts 100.00% <ø> (ø)
src/i18n/languages/huHU.ts 100.00% <ø> (ø)
src/i18n/languages/idID.ts 100.00% <ø> (ø)
src/i18n/languages/itIT.ts 100.00% <ø> (ø)
... and 10 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant