Tool · Google Sheets
See what a cell will actually do
Paste a pattern. This tells you which parts Google Sheets will reject before you find out the hard way, in a cell, with no explanation.
Why your regular expression works everywhere except Google Sheets
You found a pattern on Stack Overflow. You tested it on regex101, and it lit up green. You
pasted it into a cell and Google Sheets said #REF!.
So you went looking for a broken reference. You checked whether you had deleted a column. You
checked the sheet name. You rewrote the formula to point somewhere else, and it still said
#REF!, and by then you had lost twenty minutes to a problem that was never about
references at all.
There is no broken reference, and there is no typo. Google Sheets and every regex tool you have ever used are running different regular expression engines, they disagree about what a regular expression even is, and when they disagree, Sheets reports it with an error code that describes something else entirely.
Sheets runs RE2
Google's help page for REGEXMATCH contains one sentence that explains almost
every problem people have with these functions:
Google products use RE2 for regular expressions. Google Sheets supports RE2 except Unicode character class matching.
RE2 is a regex engine that Google wrote and open-sourced. Its defining property is a
guarantee: it will always finish, in time proportional to the length of your text, no matter
what pattern you give it. That sounds obvious until you learn that the engines inside
JavaScript, Python, Java, PHP and Perl offer no such promise. Hand them a pattern like
(a+)+b and thirty as, and they can spin for longer than the universe
has existed. It is a real class of denial-of-service attack, and it has taken down real
websites.
Google runs regular expressions from millions of spreadsheets on its own servers. It cannot allow a formula in your budget tracker to occupy a machine for a week. So it uses an engine that mathematically cannot do that — and the price of the guarantee is that certain features have to go.
What had to go
The features RE2 gives up are, almost perfectly, the features people reach for first.
Lookaround. (?=…) and (?<=…) let you say "match
this, but only if it is followed by that." They are how most people extract a number that
comes after a word. They require the engine to try a match, back up, and try again — which is
exactly the backtracking RE2 refuses to do. In a cell, both return #REF!.
Backreferences. (\w+)\s+\1 — "a word, then the same word again"
— needs the engine to remember what it captured and compare against it mid-match. RE2 cannot.
Confusingly, backreferences do exist in REGEXREPLACE, in the replacement
text. They just are not written the way RE2's own documentation writes them. More on that
below, because this is where even careful people get caught.
Possessive quantifiers, atomic groups, recursion, \K. All of
them exist to control backtracking. In an engine that never backtracks, they are meaningless,
so they are syntax errors.
The error tells you about the wrong problem
#REF! means, to anyone who has used a spreadsheet for more than a week, that a
formula is pointing at a cell that no longer exists. It is the error you get after deleting a
column. It has nothing to do with regular expressions, and it is what Sheets shows you when
your regular expression is invalid.
We did not want to take one measurement's word for that, so we asked Sheets a second time, using its own function for interrogating errors:
=ERROR.TYPE(REGEXMATCH("abc123", "abc(?=123)")) → 4 ERROR.TYPE returns 3 for #VALUE!, 7 for
#N/A, 8 for #ERROR! — and 4 for
#REF!. Two independent measurements, one answer. Google classifies an
unsupported regular expression as a broken reference.
There is a real hint buried in the cell, but you have to know to look for it: hover over the
red triangle and Sheets will tell you "…is not a valid regular expression." Almost
nobody hovers. They see #REF!, and they start deleting things.
And it can hide from you completely
Here is the part that should worry anyone who has wrapped a formula in IFERROR
to tidy up a report:
=IFERROR(REGEXMATCH("abc123", "abc(?=123)"), "caught") → caught IFERROR swallows it. A pattern that Google cannot even parse becomes a clean,
quiet fallback value, and the spreadsheet looks fine. It will keep looking fine for as long as
nobody checks. If you have IFERROR wrapped around a REGEXEXTRACT
somewhere in a monthly report, it is worth taking the wrapper off once and seeing what is
underneath.
And one thing that went only in Sheets
Read that sentence from Google's docs again: "supports RE2 except Unicode character class matching."
RE2 itself supports \p{L} — "any letter, in any alphabet." It works in
Go. It works in BigQuery. It works in every other place Google ships RE2. It does not work in
Google Sheets, and Google says so in a single subordinate clause that almost nobody reads to
the end of.
This is the cruellest one, because it catches the people who did their homework. If you looked
up RE2's syntax before writing your pattern, you would have concluded that
\p{L}+ was safe. It is not. In a cell it is #REF!, and the
documentation that told you it would work was documentation for a different product.
The replacement string speaks another language
REGEXREPLACE has a trap that is genuinely difficult to reason your way out of,
because two reasonable sources disagree.
RE2's own documentation writes a backreference in replacement text as \1. Google
Sheets wants $1. So the correct way to swap two words is:
=REGEXREPLACE("John Smith", "(\w+) (\w+)", "$2 $1")
Write "\2 \1" instead and you do not get an error. You get this:
=REGEXREPLACE("John Smith", "(\w+) (\w+)", "\2 \1") → 2 1
The backslashes vanish. What is left in the cell is the literal text 2 1. No red
triangle, no error code, nothing to notice — just a column of numbers where names used to be.
This is worse than #REF! in every way that matters, because an error at least
tells you to stop.
There is one more edge in here. If your replacement refers to a group your pattern never
captured — "[$1]" against a pattern with no parentheses — the cell returns
#N/A. Not an empty string, not #REF!. A third error, for a third
reason. The tool above counts your capture groups and says so before you paste.
The other half of the problem: quotes
Even a valid pattern fails if the formula around it is malformed, and one rule catches almost everybody. Inside a Google Sheets string, a double quote is written twice. A pattern that needs to match a quotation mark looks like this:
=REGEXEXTRACT(A1, """([^""]+)""") That is not a mistake. It is one opening quote, two escaped quotes, and so on. Nothing about it is intuitive, which is why the tool at the top of this page writes the formula for you and escapes the quotes as it goes. Copy the line, paste it in a cell, and it works.
What this tool does, and what it cannot do
A browser cannot run RE2. It has JavaScript's regex engine and nothing else. So a tool that
simply evaluates your pattern in the browser and shows you the result will happily give you a
green light for (?<=Invoice )\d+ — and that green light is a lie. This is
precisely what every general-purpose regex tester on the internet does to a Sheets user.
This tool does something different. It reads your pattern and looks for the constructs that a
real Google Sheet rejected when we ran them. If it finds one, it shows you #REF!,
even though the browser it is running in could evaluate the pattern without complaint. It
reports the spreadsheet, not the browser.
Where it finds nothing to object to, it evaluates the pattern in JavaScript and says so,
plainly, in the line under the result. Before it does, it rewrites your replacement string
into the dialect JavaScript speaks — turning \2 into a bare 2 and
$0 into the whole match — because those are the two places the engines differ,
and we measured exactly how. The preview reproduces what the sheet returned. We check that in
a test, every build.
Every rule in the list above was written as a formula, sent to Google's servers through the Sheets API, and its return value recorded with a timestamp. Not remembered from documentation. Not predicted by a model. Executed. Read the log — including the rows where the result surprised us.
When a new pattern gets verified, I'll tell you
One email when a new formula is executed, logged, and published. Nothing else. Unsubscribe in one click.