TEXTAFTER slices a string at one chosen occurrence of a delimiter and returns everything to the
right of it.
State it as an indexing problem, because that is what it is. Let t be the text and d the
delimiter. Under the chosen match mode, enumerate the occurrences of d inside t in
left-to-right order as index pairs (start_1, end_1), (start_2, end_2), …, (start_k, end_k), where
end_i = start_i + len(d). The instance_num argument selects one of them: a positive n selects
the n-th pair counted from the left, a negative n selects the |n|-th counted from the right.
The result is the substring of t from the selected end_i to the end of t.
Three consequences follow directly and are worth stating rather than discovering:
The delimiter itself is not in the result. The cut is at end_i, not start_i. That is the
entire difference between this function and TEXTBEFORE, which cuts at
start_i and keeps the left side.
A delimiter at the very end of t yields the empty string, not a missing value. end_k
equals len(t) and the substring is empty. Empty text is a perfectly good result here.
Selection is by occurrence, not by position. There is no "find the delimiter nearest
character 12" mode. If you want positional slicing, you want MID/LEFT/RIGHT, not this
family.
The string being searched. Wildcards are not accepted; the delimiter is matched literally.
delimiter
yes
The string that marks the cut point. May be more than one character.
instance_num
no
Which occurrence to cut at. Defaults to 1. Negative counts from the end. 0 is documented as an error.
match_mode
no
0 (default) case-sensitive, 1 case-insensitive.
match_end
no
0 (default) plain matching; 1 treats the end of the text as a delimiter.
if_not_found
no
The value returned instead of #N/A when the requested occurrence does not exist.
The argument position readers misjudge most often is the third. instance_num is an occurrence
index, and it is signed; it is not a character position and not a count of characters to skip.
TEXTAFTER("a-b-c", "-", 2) is "c", and TEXTAFTER("a-b-c", "-", -1) is also "c" — the same
answer arrived at from opposite ends, which is why writing -1 is the robust way to say "after the
last one".
The sixth argument is the one people forget exists. if_not_found removes the need to wrap the
call in IFERROR, and unlike IFERROR it only catches the no-match case: an argument-domain error
still surfaces.
Try it
Quirks
Result and edge cases
The return kind is Text — a scalar string, including possibly the empty string. This function
is not itself array-producing; it is a scalar kernel that the engine lifts. The lifting rules,
including how a per-element failure stays element-local rather than collapsing the whole result,
are in coercion and lifting; the spill mechanics are the
host-side adaptation step described in the call pipeline.
Other boundaries worth naming explicitly:
Numbers and logicals as text or delimiter. They convert to text by the ordinary rules in
coercion and lifting; TRUE becomes the string TRUE.
Nothing here is special-cased.
An empty referenced cell delivers Empty, which is distinct from an omitted argument. See
the value universe for why the two are kept apart.
Error inputs propagate. Coercion never discards a worksheet error.
Empty result versus no result. These are different outcomes and should not be conflated by a
caller: an empty string means the cut succeeded and nothing followed it; #N/A (or
if_not_found) means no such occurrence existed.
Errors
Microsoft's page documents the following (see Sources):
Error
Documented condition
#N/A
The delimiter is not found, or instance_num exceeds the number of occurrences.
#VALUE!
instance_num is 0, or its magnitude exceeds the length of the text.
#N/A is suppressible by supplying if_not_found; #VALUE! is not. Errors arriving in any
argument propagate ahead of all of this. Empty text gives #N/A, not #VALUE!, even though the
default instance_num of 1 exceeds its length of 0 (FN-TEXTSPLIT-001).
Empty text gives #N/A from TEXTBEFORE and TEXTAFTER, #VALUE! from TEXTSPLIT
An empty string as text gives #N/A (delimiter not found) from TEXTBEFORE and TEXTAFTER, but #VALUE! from TEXTSPLIT.
Formula
Excel
Mathematical value
=TEXTBEFORE("","-") Excel build not recorded in this run; bulk captures of the same date (2026-09-29) record Excel 16.0 build 20430, Windows 64-bit, workbook compatibility 2Inputs and reference value
Typed formula.
#N/A
—
=TEXTAFTER("","-") Excel build not recorded in this run; bulk captures of the same date (2026-09-29) record Excel 16.0 build 20430, Windows 64-bit, workbook compatibility 2Inputs and reference value
Typed formula.
#N/A
—
=TEXTSPLIT("",",") Excel build not recorded in this run; bulk captures of the same date (2026-09-29) record Excel 16.0 build 20430, Windows 64-bit, workbook compatibility 2Inputs and reference value
Occurrence enumeration for multi-character delimiters needs an overlap policy. Scanning
"aaa" for "aa" yields two occurrences if you advance by one character and one occurrence if
you advance past the match. The documentation does not state which Excel does. Pick one, write
it down, and treat it as a probe target rather than an assumption.
Negative instance_num should be resolved against the same occurrence list, not by
re-scanning right-to-left. A right-to-left scan can disagree with a left-to-right scan for
overlapping delimiters, and the difference is exactly the overlap policy above.
Case-insensitive matching is not one rule. The upstream slice contract records only ASCII
case folding as observed; Unicode case folding, and locale-sensitive folding in particular, are
outside what that evidence covers. An implementation that folds with a full Unicode table may
find more occurrences than Excel does.
Indices are UTF-16 code units in the model this Handbook uses. Delimiters and text
containing astral characters make the distinction between code units and Unicode scalars
observable; see the value universe.
Lift only the positions you have evidence for. Lifting the delimiter position because it
seems symmetric is precisely the kind of invented behaviour this Handbook is trying not to ship.
Rust code
Show the CalcFunc source of this function
Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.
No implementation has been published with a Handbook test suite for this function.
Version differences
No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.
Alternatives
Relationships
TEXTBEFORE — the mirror function, same arguments, opposite side of the
cut. The two share one implementation module upstream, which is why their behavioural questions
are usually settled together.
TEXTSPLIT — the same delimiter idea taken to its conclusion: instead of
selecting one occurrence, split at all of them and return the pieces as an array.
MID, LEFT, RIGHT — positional slicing. Reach for these when you know the character index;
reach for TEXTAFTER when you know the marker.
FIND / SEARCH combined with MID is the pre-2022 idiom this function replaces. FIND is
case-sensitive and SEARCH is not, which is the same distinction match_mode now expresses in
one argument.
Nothing is superseded by TEXTAFTER; the older idiom remains fully supported.