Regular expressions
A regular expression is a compact text pattern that describes the shape of a text, such as an invoice number or an IBAN, so that Excel can test, extract or replace it.
Last updated: 23 October 2026
Explains: regular expression
What it is: A regular expression is a text pattern in a compact notation. ^INV-[0-9]{6}$ stands for "INV-, exactly six digits, nothing else".
Why it matters: Reference numbers follow schemes, and bank text and exports hide codes inside longer texts. A wildcard cannot say "exactly six digits" or "INV or CN"; a regular expression can. In Microsoft 365 you use it to validate invoice numbers and IBANs, pull keys out of bank descriptions and look up on a pattern.
What a regular expression is
A regular expression (regex) is a text pattern in a compact notation that describes the shape of a text. The pattern ^INV-[0-9]{6}$ says: the text starts with INV-, then comes exactly six digits, and nothing follows. A wildcard can only say "any characters"; a regular expression can say how many, of which kind, and which alternatives are allowed.
An auditor meets regular expressions wherever a code has to follow a scheme or sits inside free text:
- reference schemes: invoice numbers, Dutch IBANs, VAT numbers (
NL, 9 digits,B, 2 digits) and postcodes - bank statement lines, where the customer types the invoice number anywhere in the description
- exports that pack several fields into one cell, such as
VRK|25-0388|D1002|21%
Excel reads the PCRE2 flavor of regular expressions, in Microsoft 365 only. Three rules decide most results:
- the pattern may match anywhere in the text; only
^and$pin it to the start and the end - the match is case sensitive unless you ask otherwise
- inside an Excel string a backslash stays a single
\, and a double quote is written as""
The tokens that matter in finance data
A pattern is built from literal characters, which match themselves, and tokens, which have a special meaning. The table lists the tokens you need for reference numbers and bank text. A character class such as [A-Z] or [0-9] matches one character from the set; \d is another way to write a digit.
A token applies to the item directly before it. In [0-9]{6} the {6} counts the digits of the class; in (INV|CN) the brackets make INV|CN one item.
| Token | Meaning | Example pattern | Matches |
|---|---|---|---|
^ | Start of the text | ^INV | INV-250412, but not XINV-250412 |
$ | End of the text | 412$ | INV-250412, but not INV-4125 |
\d | One digit, the same as [0-9] | 25-\d\d | 25-04 inside 25-0412, but not 25-AB |
[A-Z] | One character from the set or range | [CD]2001 | C2001 and D2001, but not E2001 |
[^A-Z] | Not: any one character that is not in the set (the ^ must be the first character inside the brackets) | [^A-Za-z0-9] | The space, dot and hyphen in NL91 ABNA.0417-1643, so REGEXREPLACE can delete every separator in one pass |
{n} | Exactly n times the item before it | [0-9]{6} | 250412, but not 25041 (five digits) |
{n,m} | Between n and m times | ^INV-[0-9]{4,6}$ | INV-2504 and INV-250412, but not INV-250 or INV-2504123 |
. | Any one character | 25.04 | 25-04, 25X04 and also 25.04 |
+ | One or more times | ^INV-[0-9]+$ | INV-2 and INV-250412, but not INV- |
? | The item before it is optional (zero or one time) | ^[1-9][0-9]{3} ?[A-Z]{2}$ | A postcode with or without the space: 1011 AB and 1011AB |
| | Or: the left side or the right side | VRK|MEM | Any text that contains VRK or MEM |
( ) | Groups items; REGEXEXTRACT and REGEXREPLACE can pick up the group | ^(INV|CN)-[0-9]{6}$ | INV-250412 and CN-250412 |
\. | A real dot (the backslash removes the special meaning) | ^[0-9]+\.[0-9]{2}$ | 1250.00, but not 1250,00 or 125000 |
(?i) | At the start of a pattern: ignore upper and lower case | (?i)^inv-[0-9]{6}$ | INV-250412, inv-250412 and Inv-250412 |
Wildcards versus regular expressions
A wildcard pattern and a regular expression look alike but work differently. A wildcard pattern is compared with the whole text, so INV* means "starts with INV". A regular expression is searched anywhere in the text, so INV already means "contains INV" and you add ^ and $ when the whole text must fit.
The table shows what each can say. The three rows from "Exactly six digits" to "An optional space" are out of reach for wildcards.
| You want | Wildcard | Regular expression |
|---|---|---|
| Any run of characters | * | .* |
| Exactly one character | ? | . |
| Contains INV | *INV* | INV |
| Starts with INV | INV* | ^INV |
| The whole text must fit | Always the case | Add ^ and $ |
| Exactly six digits | Cannot be said | [0-9]{6} |
| INV or CN | Cannot be said | (INV|CN) |
| An optional space | Cannot be said | [ ]? |
| Upper and lower case | Ignored | Matters; (?i) ignores it |
| A real asterisk | ~* | \* |
Where regular expressions work in Excel
Watch out: Everything on this page is Microsoft 365 only. In Excel 2021 or 2024 XLOOKUP and XMATCH return #VALUE! for match mode 3, and the three REGEX functions are not available.
Five functions read a regular expression. The criteria of SUMIFS, COUNTIFS and the other conditional functions do not: they read only wildcards. Older Excel versions need Power Query or VBA for patterns.
| Function or tool | Reads a pattern? | How |
|---|---|---|
REGEXTEST | Yes | The second argument; TRUE when the pattern is found anywhere in the text. |
REGEXEXTRACT | Yes | The second argument; returns the first match, all matches or the groups, always as text. |
REGEXREPLACE | Yes | The second argument; replaces the matches, and $1 and $2 insert groups. |
XLOOKUP, XMATCH | Yes, with match mode 3 | The lookup value is the pattern; case sensitive unless it starts with (?i). |
SUMIFS, COUNTIFS | No | Wildcards only. Count with SUMPRODUCT and REGEXTEST instead. |
FILTER | Not directly | Use REGEXTEST as the include argument. |
| Find and Replace (Ctrl+F, Ctrl+H) | No | Wildcards only. Use REGEXREPLACE in a helper column. |
Test: does the text follow the scheme?
=REGEXTEST(B2,"^INV-[0-9]{6}$")
=REGEXTEST(B2;"^INV-[0-9]{6}$")
TRUE when B2 is INV- followed by exactly six digits, and nothing else.
Extract: pull a number out of text.
=VALUE(REGEXEXTRACT(B2,"[0-9]{6}"))
=VALUE(REGEXEXTRACT(B2;"[0-9]{6}"))
The first run of six digits in B2. REGEXEXTRACT returns text, so VALUE turns it into a number.
Replace: rearrange with groups.
=REGEXREPLACE(B2,"^INV-([0-9]{2})([0-9]{4})$", "$1-$2")
=REGEXREPLACE(B2;"^INV-([0-9]{2})([0-9]{4})$"; "$1-$2")
INV-250412 becomes 25-0412: group 1 holds the first two digits, group 2 the last four.
Look up: the lookup value is a pattern.
=XLOOKUP("^INV-10(02|04)$",A2:A7, B2:B7, "Not found", 3)
=XLOOKUP("^INV-10(02|04)$";A2:A7; B2:B7; "Not found"; 3)
Match mode 3 is the fifth argument in XLOOKUP and the third in XMATCH. The first cell of A2:A7 that is INV-1002 or INV-1004 wins.
Reading a pattern step by step
Read a pattern from left to right and cut it into pieces at each token. A Dutch IBAN is NL, 2 digits, 4 letters and 10 digits, 18 characters in all. As a pattern: ^NL[0-9]{2}[A-Z]{4}[0-9]{10}$.
The pattern checks the shape, not the content: it does not test the check digits, so a mistyped digit still passes. A lowercase nl91... fails because of the case sensitivity, and an IBAN printed in groups (NL91 ABNA 0417 1643 00) or with dots and hyphens fails because of the separators. Clean it first with a negated class: [^A-Za-z0-9] is "any character that is not a letter or digit", so REGEXREPLACE with that pattern deletes every separator in one pass, whichever ones a client used, and UPPER takes care of the case.
| Piece | Reads as | In NL91ABNA0417164300 |
|---|---|---|
^ | The text starts here | Nothing before the N |
NL | The two letters NL, as typed | NL |
[0-9]{2} | Exactly two digits | 91, the check digits |
[A-Z]{4} | Exactly four capital letters | ABNA, the bank code |
[0-9]{10} | Exactly ten digits | 0417164300, the account number |
$ | The text ends here | Nothing after the last 0 |
=REGEXTEST(B2,"^NL[0-9]{2}[A-Z]{4}[0-9]{10}$")
=REGEXTEST(B2;"^NL[0-9]{2}[A-Z]{4}[0-9]{10}$")
TRUE for NL91ABNA0417164300: 2 + 2 + 4 + 10 = 18 characters in the right order.
=REGEXTEST(UPPER(REGEXREPLACE(B2,"[^A-Za-z0-9]", "")), "^NL[0-9]{2}[A-Z]{4}[0-9]{10}$")
=REGEXTEST(UPPER(REGEXREPLACE(B2;"[^A-Za-z0-9]"; "")); "^NL[0-9]{2}[A-Z]{4}[0-9]{10}$")
Also TRUE for nl91 abna.0417-1643 00: the negated class deletes the spaces, dot and hyphen, UPPER fixes the case, and only then is the shape tested.
Worked examples
Example1 of 3Beginner
Check that invoice numbers follow the INV- scheme
The sales ledger of Veldhuis Installatie BV numbers its invoices as INV- followed by six digits. Before you test the completeness of the numbering, you want to flag every number in the export that does not follow that scheme.
Column C shows TRUE or FALSE per invoice number.
| Row | A | B | C | D |
|---|---|---|---|---|
| 1 | Invoice no. | Customer | Valid? | |
| 2 | INV-250412 | Dekker Installatie BV | TRUE=REGEXTEST(A2, "^INV-[0-9]{6}$")=REGEXTEST(A2; "^INV-[0-9]{6}$") | |
| 3 | INV-25412 | Van Rijn Vastgoed BV | FALSE=REGEXTEST(A3, "^INV-[0-9]{6}$")=REGEXTEST(A3; "^INV-[0-9]{6}$") | |
| 4 | inv-250413 | Hofman Aannemers | FALSE=REGEXTEST(A4, "^INV-[0-9]{6}$")=REGEXTEST(A4; "^INV-[0-9]{6}$") | |
| 5 | INV-2504140 | Mulder Horeca | FALSE=REGEXTEST(A5, "^INV-[0-9]{6}$")=REGEXTEST(A5; "^INV-[0-9]{6}$") | |
| 6 | INV 250415 | Ouwerkerk Logistiek | FALSE=REGEXTEST(A6, "^INV-[0-9]{6}$")=REGEXTEST(A6; "^INV-[0-9]{6}$") | |
| 7 | INV-250416 | Kuipers Techniek BV | TRUE=REGEXTEST(A7, "^INV-[0-9]{6}$")=REGEXTEST(A7; "^INV-[0-9]{6}$") | |
| 8 | INV-25O417 | Smeets Groothandel | FALSE=REGEXTEST(A8, "^INV-[0-9]{6}$")=REGEXTEST(A8; "^INV-[0-9]{6}$") | |
| 9 |
Swipe sideways to see all columns
Formula in C2
=REGEXTEST(A2,"^INV-[0-9]{6}$")
=REGEXTEST(A2;"^INV-[0-9]{6}$")
Result: TRUE
Step by step
- The pattern is
^INV-[0-9]{6}$.^fixes the start,INV-must be typed exactly like this in capitals,[0-9]{6}is exactly six digits and$fixes the end. REGEXTEST looks for the pattern anywhere in the text, so the two anchors are what turn this into a check on the whole cell. A2holdsINV-250412: it starts withINV-, then come the six digits 2, 5, 0, 4, 1 and 2, and then the text ends. TRUE.A3holdsINV-25412: only five digits, and the pattern needs six before the end. FALSE.A4holdsinv-250413: the pattern is case sensitive by default, soinv-does not fitINV-. FALSE.A5holdsINV-2504140: after six digits (250414) a seventh digit follows, but$needs the end of the text. FALSE.A6holdsINV 250415: a space where the pattern needs a hyphen. FALSE.A7holdsINV-250416: TRUE.A8holdsINV-25O417, with the capital letter O instead of a zero in the third position after the hyphen. A letter is not in[0-9]. FALSE.C2shows TRUE; copied down,C3toC8show FALSE, FALSE, FALSE, FALSE, TRUE and FALSE. Two of the seven numbers follow the scheme, so five go on your list of exceptions.
Watch out: Leave out the anchors, as in INV-[0-9]{6}, and A5 (INV-2504140) passes: six digits are found inside the seven. Test on the whole cell with ^ and $.
More on this example: why it works, 1 more pitfall, 2 variations
Why it works
REGEXTEST asks whether the pattern occurs in the text, not whether the text equals the pattern. ^ and $ close both ends, and {6} fixes the number of digits, which a wildcard cannot do.
The check says whether the number has the right form. It does not say that the invoice exists.
More to watch out for
- Look-alike characters fail the test on purpose: a letter O for a zero, an en dash for a hyphen. The result is FALSE and the cell looks right, so check the flagged numbers character by character.
Variations
=REGEXTEST(A2,"^INV-[0-9]{6}$", 1)
=REGEXTEST(A2;"^INV-[0-9]{6}$"; 1)
The third argument 1 ignores case. A4 (inv-250413) now passes, so the numbers that follow the scheme go from 2 to 3. Writing (?i) at the start of the pattern does the same.
=SUMPRODUCT(--REGEXTEST(A2:A8,"^INV-[0-9]{6}$"))
=SUMPRODUCT(--REGEXTEST(A2:A8;"^INV-[0-9]{6}$"))
Counts the numbers that follow the scheme in one cell: the result is 2 (A2 and A7).
Example2 of 3Intermediate
Find the customer behind a bank statement line
A customer paid Veldhuis Installatie BV and typed the invoice number somewhere in the bank description. You want to know which customer the line belongs to, using the debtor list of the client.
E1 holds the bank description. The invoice number can sit anywhere in it, so a fixed position (LEFT, MID) does not work.
| Row | A | B | C | D | E | F |
|---|---|---|---|---|---|---|
| 1 | Invoice no. | Customer | Bank description | SEPA OVERBOEKING HOFMAN AANNEMERS BETALING FACTUUR INV-250418 DD 14-10-2025 | ||
| 2 | INV-250412 | Dekker Installatie BV | Customer | Hofman Aannemers=XLOOKUP(REGEXEXTRACT(E1, "INV-[0-9]{6}"), A2:A7, B2:B7, "Not found")=XLOOKUP(REGEXEXTRACT(E1; "INV-[0-9]{6}"); A2:A7; B2:B7; "Not found") | ||
| 3 | INV-250415 | Van Rijn Vastgoed BV | ||||
| 4 | INV-250418 | Hofman Aannemers | ||||
| 5 | INV-250421 | Ouwerkerk Logistiek | ||||
| 6 | INV-250427 | Mulder Horeca | ||||
| 7 | INV-250433 | Kuipers Techniek BV | ||||
| 8 |
Swipe sideways to see all columns
Formula in E2
=XLOOKUP(REGEXEXTRACT(E1,"INV-[0-9]{6}"), A2:A7, B2:B7, "Not found")
=XLOOKUP(REGEXEXTRACT(E1;"INV-[0-9]{6}"); A2:A7; B2:B7; "Not found")
Result: Hofman Aannemers
Step by step
- Excel evaluates the inner function first: REGEXEXTRACT on
E1with the patternINV-[0-9]{6}, that isINV-and six digits. The fourth argument of XLOOKUP is not involved yet. There are no anchors, because the number is inside a longer text and REGEXEXTRACT has to find it, not test the whole text. - The words SEPA, OVERBOEKING, HOFMAN, AANNEMERS, BETALING and FACTUUR contain no
INV-. InFACTUUR INV-250418the pattern fits:INV-, then 2, 5, 0, 4, 1, 8 are six digits. The next character is a space, so the match ends there. The default return mode 0 returns the first match as text:INV-250418. The date14-10-2025has noINV-and is never reached. - XLOOKUP now looks up the text
INV-250418inA2:A7with the default exact match.A2(INV-250412): no.A3(INV-250415): no.A4(INV-250418): yes, the third item. - XLOOKUP returns the third item of
B2:B7, which isB4:Hofman Aannemers. - Type
BETALING INV-250433 KUIPERS TECHNIEKinE1and REGEXEXTRACT returnsINV-250433, the sixth item, so the result isKuipers Techniek BV. The formula follows the number wherever it sits in the text.
Watch out: A bank line without an invoice number, such as TERUGBETALING BTW 3E KWARTAAL, makes REGEXEXTRACT return #N/A. The error from REGEXEXTRACT is what you see: the Not found message is not shown, because it only covers a key that is missing from the list. Wrap the formula in IFNA (first variation).
More on this example: why it works, 1 more pitfall, 2 variations
Why it works
REGEXEXTRACT turns free text into a clean key, and XLOOKUP does what it always does with a key: an exact lookup. The two jobs stay separate, so you can check the extracted key on its own.
The text before and after the number does not matter. Only the shape INV- plus six digits is searched.
More to watch out for
- A longer digit string is cut after six digits.
FACT INV-2504181 HOFMANgivesINV-250418and so the wrong customer. End the pattern with(?![0-9]), which means "not followed by another digit":INV-[0-9]{6}(?![0-9])then finds no match in that text, and you see the #N/A.
Variations
=IFNA(XLOOKUP(REGEXEXTRACT(E1,"INV-[0-9]{6}"), A2:A7, B2:B7), "No invoice number found")
=IFNA(XLOOKUP(REGEXEXTRACT(E1;"INV-[0-9]{6}"); A2:A7; B2:B7); "No invoice number found")
IFNA catches the #N/A from REGEXEXTRACT as well as from XLOOKUP. With the bank line above the result is still Hofman Aannemers; with TERUGBETALING BTW 3E KWARTAAL it shows the message.
=VALUE(REGEXEXTRACT(E1,"[0-9]{6}"))
=VALUE(REGEXEXTRACT(E1;"[0-9]{6}"))
Only the number, as a real number: 250418. REGEXEXTRACT returns text, so VALUE is needed before you calculate with it. The first run of six digits is 250418; the date digits come in groups of 2 and 4.
Example3 of 3Advanced
Find the amount of the last sales entry of a customer
An export of Veldhuis Installatie BV packs the journal, the entry number, the relation and the VAT rate into one key per line, separated by pipes: VRK|25-0407|D1002|21%.
You want the amount of the last sales entry (journal VRK) of the customer in E1. A memorial entry (MEM) for the same customer comes later in the list and must not count.
| Row | A | B | C | D | E | F |
|---|---|---|---|---|---|---|
| 1 | Journal key | Amount | Customer | D1002 | ||
| 2 | VRK|25-0388|D1002|21% | €1,210.00€ 1.210,00 | Amount | €2,420.00€ 2.420,00=XLOOKUP("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|", A2:A8, B2:B8, "Not found", 3, -1)=XLOOKUP("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|"; A2:A8; B2:B8; "Not found"; 3; -1) | ||
| 3 | VRK|25-0391|D1005|21% | €605.00€ 605,00 | ||||
| 4 | VRK|25-0395|D1002|9% | €218.00€ 218,00 | ||||
| 5 | INK|25-0402|C2001|21% | €363.00€ 363,00 | ||||
| 6 | VRK|25-0407|D1002|21% | €2,420.00€ 2.420,00 | ||||
| 7 | VRK|25-0409|D1020|21% | €726.00€ 726,00 | ||||
| 8 | MEM|25-0414|D1002|21% | €150.00€ 150,00 | ||||
| 9 |
Swipe sideways to see all columns
Formula in E2
=XLOOKUP("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|",A2:A8, B2:B8, "Not found", 3, -1)
=XLOOKUP("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|";A2:A8; B2:B8; "Not found"; 3; -1)
Result: €2,420.00€ 2.420,00
Step by step
E1holdsD1002. The three pieces join into the pattern^VRK\|[0-9]{2}-[0-9]{4}\|D1002\|. Read it in parts:^VRKthe key starts with VRK;\|a real pipe, because a bare|would mean "or";[0-9]{2}-[0-9]{4}an entry number such as 25-0407;D1002the customer;\|a real pipe after it.- The fifth argument 3 is the match mode for regular expressions: the lookup value is read as a pattern, and a cell matches when the pattern is found in it. The sixth argument -1 searches from the last cell to the first.
- XLOOKUP starts at the bottom of
A2:A8.A8(MEM|25-0414|D1002|21%): the customer fits but the key starts with MEM, and^VRKfails. No.A7(VRK|25-0409|D1020|21%): VRK and an entry number fit, but after the pipe the pattern needsD1002|and the text hasD1020|. No. A6(VRK|25-0407|D1002|21%): VRK, entry number 25-0407, D1002 and a pipe all fit. Yes, and the search stops.A6is the fifth item ofA2:A8, so XLOOKUP returns the fifth item ofB2:B8, which isB6: €2,420.00€ 2.420,00.- Without the sixth argument the search runs from the top and stops at
A2(VRK|25-0388|D1002|21%): €1,210.00€ 1.210,00, the first entry instead of the last. Without^VRKin the pattern the last hit would be the memorial entryA8: €150.00€ 150,00. - Change
E1toD1005and onlyA3fits (VRK|25-0391|D1005|21%): the result is €605.00€ 605,00, whichever direction you search.
Watch out: An unescaped pipe changes the pattern into alternatives. ^VRK|[0-9]{2}-[0-9]{4}|D1002| ends with an empty alternative that fits every text, so A8 is found first from the bottom and the result is €150.00€ 150,00. Always write \| for a real pipe.
More on this example: why it works, 2 more pitfalls, 2 variations
Why it works
In match mode 3 the cell has to contain the pattern, so the anchor ^ and the closing pipe decide which cells count: the journal at the start and the whole customer code, so D1002 never fits D10025.
The search mode still works as usual: -1 returns the last match. Binary search (2 or -2) makes no sense with a pattern, because the list is not sorted by what the pattern describes.
More to watch out for
- Mode 3 is case sensitive. With
d1002inE1nothing fits and you seeNot found. Start the pattern with(?i)to ignore case, as in "(?i)^VRK...". - In Excel 2021 or 2024 this formula returns #VALUE!, because match mode 3 exists only in Microsoft 365. Check the version of everyone who opens the file.
Variations
=XMATCH("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|",A2:A8, 3, -1)
=XMATCH("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|";A2:A8; 3; -1)
The position instead of the amount: 5, the fifth cell of A2:A8. In XMATCH the match mode is the third argument and the search mode the fourth.
=XLOOKUP("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|",A2:A8, B2:B8, "Not found", 3)
=XLOOKUP("^VRK\|[0-9]{2}-[0-9]{4}\|" & E1 & "\|";A2:A8; B2:B8; "Not found"; 3)
Without the search mode the first match counts: €1,210.00€ 1.210,00, the entry in A2.
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| REGEXTEST returns TRUE for a number that is too long | INV-2504140 (seven digits) passes the test INV-[0-9]{6}. | The pattern is searched anywhere in the text, and six digits do occur inside seven. Add ^ at the start and $ at the end when the whole cell must fit. |
| Lowercase invoice number is rejected | The pattern ^INV-[0-9]{6}$ gives FALSE for inv-250413. | Regular expressions are case sensitive by default, unlike wildcards. Start the pattern with (?i), or set the case sensitivity argument of the REGEX functions to 1. |
| A pattern matches more than expected | 25.04 also matches 25X04, and VRK|25-0388 is read as two alternatives. | A . stands for any character and a | means "or". Write \. for a real dot and \| for a real pipe. The same goes for (, ), [, +, *, ? and $. |
| A sum over extracted numbers gives 0 | SUM over cells filled by REGEXEXTRACT returns 0, although the cells show numbers. | REGEXEXTRACT always returns text. Wrap it in VALUE to get a number: VALUE(REGEXEXTRACT(...)). |
| A wildcard-style pattern fits texts without INV | You write INV* as you would for a wildcard, and REGEXTEST says TRUE for BIN 12. | In a regular expression * repeats the item before it, so INV* means IN followed by zero or more V. For "INV- and anything" write INV-.*. |
| #VALUE! from XLOOKUP or XMATCH | A formula with match mode 3 works for you and returns #VALUE! for a colleague. | Match mode 3 and the REGEX functions exist only in Microsoft 365. Excel 2021 and 2024 do not support them. Check the version of every user, or use a different construction. |