<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Re2 on Serhii Chechun - Developer&#39;s Blog</title>
    <link>https://blog.chechun.org/tags/re2/</link>
    <description>Recent content in Re2 on Serhii Chechun - Developer&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>© 2026 Serhii Chechun</copyright>
    <lastBuildDate>Fri, 28 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.chechun.org/tags/re2/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Regular Expressions in Go: A Deep Dive</title>
      <link>https://blog.chechun.org/posts/regexp-in-go-deep-dive/</link>
      <pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/posts/regexp-in-go-deep-dive/</guid>
      <description>&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;regexp&lt;/code&gt; package is one of the most misunderstood pieces of the standard library. Coming from Python, JavaScript, or Ruby, the first thing most developers notice is what&amp;rsquo;s &lt;em&gt;missing&lt;/em&gt;: no &lt;code&gt;\1&lt;/code&gt; backreferences, no lookahead, no lookbehind. The second thing they notice is the scary wall of &lt;code&gt;Find&lt;/code&gt;, &lt;code&gt;FindAll&lt;/code&gt;, &lt;code&gt;FindString&lt;/code&gt;, &lt;code&gt;FindStringSubmatch&lt;/code&gt; methods.&lt;/p&gt;</description>
      <content>&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;regexp&lt;/code&gt; package is one of the most misunderstood pieces of the standard library. Coming from Python, JavaScript, or Ruby, the first thing most developers notice is what&amp;rsquo;s &lt;em&gt;missing&lt;/em&gt;: no &lt;code&gt;\1&lt;/code&gt; backreferences, no lookahead, no lookbehind. The second thing they notice is the scary wall of &lt;code&gt;Find&lt;/code&gt;, &lt;code&gt;FindAll&lt;/code&gt;, &lt;code&gt;FindString&lt;/code&gt;, &lt;code&gt;FindStringSubmatch&lt;/code&gt; methods.&lt;/p&gt;
&lt;p&gt;These surprises are not accidental. Both are the direct result of a deliberate design decision that prioritizes &lt;strong&gt;safety and predictable performance over expressiveness&lt;/strong&gt;. Once one understands &lt;em&gt;why&lt;/em&gt; Go&amp;rsquo;s regex engine works the way it does, the API stops feeling limited and starts feeling rational.&lt;/p&gt;
&lt;p&gt;This post covers the history behind the engine, how it compares to what other languages use, and how to actually read and use the full API.&lt;/p&gt;
&lt;p&gt;All the code from this post is available as runnable examples in the &lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/regular-expressions/examples&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;accompanying repository&lt;/a&gt;
.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-the-history-and-philosophy-of-gos-regexp&#34;&gt;1. The History and Philosophy of Go&amp;rsquo;s Regexp&lt;/h2&gt;
&lt;p&gt;To understand Go&amp;rsquo;s regex engine, we have to understand its lineage - it traces back more than half a century to one of the foundational figures in computer science and software engineering.&lt;/p&gt;
&lt;h3 id=&#34;the-roots-ken-thompson&#34;&gt;The Roots: Ken Thompson&lt;/h3&gt;
&lt;p&gt;In the 1960s, &lt;a href=&#34;https://en.wikipedia.org/wiki/Ken_Thompson&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ken Thompson&lt;/a&gt;
 - long before he co-created Go - was working on the &lt;a href=&#34;https://www.nokia.com/bell-labs/about/dennis-m-ritchie/qed.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;QED text editor&lt;/a&gt;
 . He wrote the first regular expression compiler for QED, and in doing so introduced what&amp;rsquo;s now known as the &lt;a href=&#34;https://en.wikipedia.org/wiki/Thompson%27s_construction&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Thompson NFA&lt;/a&gt;
 (Nondeterministic Finite Automaton) construction algorithm.&lt;/p&gt;
&lt;p&gt;The insight was elegant: a regular expression can be mechanically translated into a state machine. That state machine can then scan a string &lt;strong&gt;character by character, in a single forward pass&lt;/strong&gt;, and decide whether the string matches.&lt;/p&gt;
&lt;p&gt;This is the crucial property. It means the amount of work grows &lt;em&gt;linearly&lt;/em&gt; with the input, and it&amp;rsquo;s the foundation everything else in this post is built on.&lt;/p&gt;
&lt;h3 id=&#34;the-author-russ-cox&#34;&gt;The Author: Russ Cox&lt;/h3&gt;
&lt;p&gt;The Go &lt;code&gt;regexp&lt;/code&gt; package is a &lt;strong&gt;reimplementation of RE2, written in Go&lt;/strong&gt; - not the &lt;a href=&#34;https://github.com/google/re2&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;original C++ library&lt;/a&gt;
, but a faithful port of its design and behavior. RE2 itself was authored by &lt;a href=&#34;https://swtch.com/~rsc/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Russ Cox&lt;/a&gt;
, who is, at the time of this writing, the technical lead of the Go project.&lt;/p&gt;
&lt;p&gt;For a deeper dive, his article series, &lt;a href=&#34;https://swtch.com/~rsc/regexp/regexp1.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Regular Expression Matching Can Be Simple And Fast&lt;/a&gt;
, is the definitive reference.&lt;/p&gt;
&lt;h3 id=&#34;core-design-decision-safety-over-features&#34;&gt;Core Design Decision: Safety Over Features&lt;/h3&gt;
&lt;p&gt;The defining choice in Go&amp;rsquo;s regex engine is a conscious trade-off:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Guarantee linear-time execution, and refuse to support anything that would break that guarantee.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Concretely, the engine runs in &lt;strong&gt;linear time&lt;/strong&gt;: for an input of length &lt;strong&gt;n&lt;/strong&gt; and a pattern of size &lt;strong&gt;m&lt;/strong&gt;, it finishes in &lt;strong&gt;O(n * m)&lt;/strong&gt;. That&amp;rsquo;s not a &amp;ldquo;usually fast&amp;rdquo; promise - it&amp;rsquo;s a hard guarantee.&lt;/p&gt;
&lt;p&gt;This matters enormously in the real world because of &lt;a href=&#34;https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Regular Expression Denial of Service (ReDoS)&lt;/a&gt;
. An innocent-looking pattern paired with a carefully crafted input can force a backtracking engine to explore an exponential number of paths, hanging the process. It&amp;rsquo;s a real, actively exploited vulnerability in many languages.&lt;/p&gt;
&lt;p&gt;Go eliminates the entire class by construction. Untrusted user input can be run against any regex, at any time, without a timeout, and the engine will still finish in linear time.&lt;/p&gt;
&lt;h3 id=&#34;what-was-sacrificed&#34;&gt;What Was Sacrificed&lt;/h3&gt;
&lt;p&gt;This safety comes at a price. Two categories of features that are common in &lt;a href=&#34;https://www.pcre.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PCRE-style engines&lt;/a&gt;
 are &lt;strong&gt;intentionally omitted&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backreferences&lt;/strong&gt; (&lt;code&gt;\1&lt;/code&gt;, &lt;code&gt;\2&lt;/code&gt;, &amp;hellip;) - referring to a previously captured group inside the pattern.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lookaround assertions&lt;/strong&gt; - lookahead (&lt;code&gt;(?=...)&lt;/code&gt;, &lt;code&gt;(?!...)&lt;/code&gt;) and lookbehind (&lt;code&gt;(?&amp;lt;=...)&lt;/code&gt;, &lt;code&gt;(?&amp;lt;!...)&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why? Because both of these require the ability to &lt;em&gt;remember&lt;/em&gt; where you were and &lt;em&gt;backtrack&lt;/em&gt; to try alternative paths. And backtracking is exactly what destroys the linear-time guarantee - it&amp;rsquo;s what opens the door to &lt;strong&gt;O(2^n)&lt;/strong&gt; worst-case behavior and ReDoS.&lt;/p&gt;
&lt;p&gt;This is a philosophical position, not a technical oversight. In practice, most real-world regexes can be written &lt;em&gt;without&lt;/em&gt; backreferences or lookaround, and for the rare cases that genuinely need them, the linear-time guarantee is worth more than the convenience.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-engine-overview-re2-vs-the-world&#34;&gt;2. Engine Overview: RE2 vs. The World&lt;/h2&gt;
&lt;p&gt;To really appreciate Go&amp;rsquo;s approach, it helps to contrast it with what most other languages use under the hood.&lt;/p&gt;
&lt;h3 id=&#34;the-go-engine-automaton-based&#34;&gt;The Go Engine: Automaton-Based&lt;/h3&gt;
&lt;p&gt;Go compiles your regex into a &lt;strong&gt;state machine&lt;/strong&gt; (a Thompson NFA, with DFA optimizations where beneficial). It then parses the input in a &lt;strong&gt;single forward pass&lt;/strong&gt;, tracking the set of possible states as it consumes each character. Crucially, it &lt;strong&gt;never goes backward&lt;/strong&gt;. Once a character is consumed, the engine never revisits it.&lt;/p&gt;
&lt;p&gt;This single-pass property is what makes the linear-time guarantee possible. Every character is examined exactly once, and the work per character is bounded.&lt;/p&gt;
&lt;h3 id=&#34;the-competition-backtracking&#34;&gt;The Competition: Backtracking&lt;/h3&gt;
&lt;p&gt;Most other popular languages - &lt;a href=&#34;https://docs.python.org/3/library/re.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Python &lt;code&gt;re&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/util/regex/package-summary.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Java &lt;code&gt;java.util.regex&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://github.com/k-takata/onigmo&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ruby &lt;code&gt;Onigmo&lt;/code&gt;&lt;/a&gt;
, plus Perl and PHP - use &lt;strong&gt;backtracking&lt;/strong&gt; engines that share PCRE-style semantics. Strictly speaking, most aren&amp;rsquo;t literally PCRE - PHP is the exception, wrapping the real PCRE library, and PCRE itself is a C library built to emulate Perl - but they all follow the same family of design and syntax.&lt;/p&gt;
&lt;p&gt;A backtracking engine works by trying one matching path. If it fails partway through, it &amp;ldquo;rewinds&amp;rdquo; to the last decision point and tries a &lt;em&gt;different&lt;/em&gt; path. If the pattern has many such decision points (nested quantifiers, alternations, groups), the number of paths can explode.&lt;/p&gt;
&lt;p&gt;For typical patterns and inputs, backtracking is fast - often faster than an automaton-based engine, which is part of why these languages keep it. But it has no worst-case guarantee: a bad pattern and input can force exponential growth in the number of paths.&lt;/p&gt;
&lt;h3 id=&#34;the-comparison-table&#34;&gt;The Comparison Table&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Feature / Trait&lt;/th&gt;
					&lt;th&gt;Go (&lt;code&gt;regexp&lt;/code&gt; / RE2)&lt;/th&gt;
					&lt;th&gt;Backtracking engines (PCRE-style: Python, Java, Ruby, Node.js)&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Matching Algorithm&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Thompson NFA / DFA&lt;/td&gt;
					&lt;td&gt;Backtracking (usually NFA)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Worst-case Time&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Linear &lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Exponential &lt;strong&gt;O(2^n)&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ReDoS Vulnerability&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;No (safe for untrusted user input)&lt;/td&gt;
					&lt;td&gt;Yes (requires timeouts / safeguards)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Lookahead / Lookbehind&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Not supported&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Fully supported&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Backreferences (&lt;code&gt;\1&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Not supported&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Fully supported&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Execution Predictability&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Extremely high&lt;/td&gt;
					&lt;td&gt;Can be volatile on complex strings&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The trade-off in one sentence: &lt;strong&gt;backtracking engines offer more expressive power; Go&amp;rsquo;s engine offers a guarantee.&lt;/strong&gt; Which approach to choose depends entirely on whether the regexes run against trusted, known inputs or against data the system doesn&amp;rsquo;t control.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; If you&amp;rsquo;re porting a regex from Python or JavaScript to Go, and it uses lookahead, lookbehind, or backreferences, it simply &lt;strong&gt;will not compile&lt;/strong&gt;. You&amp;rsquo;ll need to rewrite it - often with more verbose alternations or by doing part of the work outside the regex.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;3-the-full-api-the-method-matrix&#34;&gt;3. The Full API: The Method Matrix&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;regexp&lt;/code&gt; API has dozens of methods, but they follow a single, consistent &lt;strong&gt;naming matrix&lt;/strong&gt;: almost every method is built by combining prefixes and suffixes:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Find (All)? (String)? (Submatch)? (Index)?
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The core is &lt;code&gt;Find&lt;/code&gt;, with optional additions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;All&lt;/code&gt; return &lt;em&gt;all&lt;/em&gt; matches (not just the first)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;String&lt;/code&gt; operate on and return &lt;code&gt;string&lt;/code&gt; instead of &lt;code&gt;[]byte&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Submatch&lt;/code&gt; also return captured groups&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Index&lt;/code&gt; return byte offsets instead of the matched text&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So &lt;code&gt;FindAllStringSubmatchIndex&lt;/code&gt; is the most complete version: &lt;em&gt;find all matches, as strings, including submatches, as byte-index pairs.&lt;/em&gt; Once the pattern is understood, the rest of the API becomes predictable.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ReplaceAll&lt;/code&gt; and &lt;code&gt;Split&lt;/code&gt; families are the exceptions to this matrix: &lt;code&gt;ReplaceAll&lt;/code&gt;/&lt;code&gt;ReplaceAllString&lt;/code&gt;, &lt;code&gt;ReplaceAllLiteral&lt;/code&gt;/&lt;code&gt;ReplaceAllLiteralString&lt;/code&gt;, and &lt;code&gt;ReplaceAllFunc&lt;/code&gt;/&lt;code&gt;ReplaceAllStringFunc&lt;/code&gt; place the &lt;code&gt;String&lt;/code&gt; suffix differently (note &lt;code&gt;ReplaceAllStringFunc&lt;/code&gt;, not &lt;code&gt;ReplaceAllFuncString&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;compilation--utility-functions&#34;&gt;Compilation &amp;amp; Utility Functions&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Function&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
					&lt;th&gt;When to use&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Compile(expr)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Compiles the regex, returns an &lt;code&gt;error&lt;/code&gt; if invalid.&lt;/td&gt;
					&lt;td&gt;User-provided or dynamic regex.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;MustCompile(expr)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Compiles the regex, &lt;strong&gt;panics&lt;/strong&gt; if invalid.&lt;/td&gt;
					&lt;td&gt;Hardcoded regex initialized globally.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;CompilePOSIX(expr)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Compiles using strict POSIX ERE rules (leftmost-longest match).&lt;/td&gt;
					&lt;td&gt;When POSIX behavior is needed.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;MatchString(pattern, s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;One-off boolean check - compiles internally.&lt;/td&gt;
					&lt;td&gt;Simple, rare checks.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;QuoteMeta(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Escapes all regex metacharacters, returns a &lt;code&gt;string&lt;/code&gt;.&lt;/td&gt;
					&lt;td&gt;Treating dynamic strings as literals.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The key distinction: &lt;code&gt;Compile&lt;/code&gt; returns an error, while &lt;code&gt;MustCompile&lt;/code&gt; panics. For a hardcoded pattern in a global &lt;code&gt;var&lt;/code&gt;, a panic on startup is usually the &lt;em&gt;right&lt;/em&gt; behavior - a typo in a constant regex is a developer bug, not a runtime condition. That&amp;rsquo;s why &lt;code&gt;MustCompile&lt;/code&gt; is the idiomatic choice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;digitsRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\d{3,4}`&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// panics at init if the pattern is bad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-regexp-object-api&#34;&gt;The &lt;code&gt;Regexp&lt;/code&gt; Object API&lt;/h3&gt;
&lt;p&gt;With a compiled &lt;code&gt;*regexp.Regexp&lt;/code&gt;, here&amp;rsquo;s the method surface. The &lt;code&gt;String&lt;/code&gt; variants work on and return &lt;code&gt;string&lt;/code&gt;; the non-&lt;code&gt;String&lt;/code&gt; variants work on &lt;code&gt;[]byte&lt;/code&gt;. The rest of the matrix composes on top.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Method&lt;/th&gt;
					&lt;th&gt;Argument Type&lt;/th&gt;
					&lt;th&gt;Returns&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Match(b)&lt;/code&gt; / &lt;code&gt;MatchString(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;True if the regex matches any part of the input.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Find(b)&lt;/code&gt; / &lt;code&gt;FindString(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The leftmost match.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;FindAll(b, n)&lt;/code&gt; / &lt;code&gt;FindAllString(s, n)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[][]byte&lt;/code&gt; / &lt;code&gt;[]string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Up to &lt;code&gt;n&lt;/code&gt; matches (&lt;code&gt;-1&lt;/code&gt; for all).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;FindSubmatch(b)&lt;/code&gt; / &lt;code&gt;FindStringSubmatch(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[][]byte&lt;/code&gt; / &lt;code&gt;[]string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The match plus all captured groups &lt;code&gt;( )&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;FindIndex(b)&lt;/code&gt; / &lt;code&gt;FindStringIndex(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]int&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[start, end]&lt;/code&gt; byte index pair (or &lt;code&gt;nil&lt;/code&gt; if no match).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReplaceAll(b, repl)&lt;/code&gt; / &lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Replaces matches with &lt;code&gt;repl&lt;/code&gt;, expanding &lt;code&gt;$1&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReplaceAllLiteral(b, repl)&lt;/code&gt; / &lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Replaces matches with the literal &lt;code&gt;repl&lt;/code&gt; string (no expansion).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReplaceAllFunc(b, repl)&lt;/code&gt; / &lt;code&gt;ReplaceAllStringFunc(s, repl)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt; (&lt;code&gt;repl&lt;/code&gt; is a &lt;code&gt;func&lt;/code&gt;)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Replaces matches using a custom function.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Split(s, n)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Splits the string around the matches.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two practical notes on this API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prefer the &lt;code&gt;[]byte&lt;/code&gt; methods&lt;/strong&gt; when working with I/O and network data. Reading a file or a socket already yields &lt;code&gt;[]byte&lt;/code&gt;; converting to &lt;code&gt;string&lt;/code&gt; forces an allocation. The &lt;code&gt;[]byte&lt;/code&gt; methods avoid that copy entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SubmatchIndex&lt;/code&gt; returns byte offsets.&lt;/strong&gt; An optional group that didn&amp;rsquo;t participate in the match reports &lt;code&gt;-1&lt;/code&gt; for both its start and end - which signals that it was absent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the &lt;code&gt;Submatch&lt;/code&gt; semantics in action:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`(?P&amp;lt;year&amp;gt;\d{4})-(?P&amp;lt;month&amp;gt;\d{2})`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatchIndex&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2026-08&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// idx = [0 7 0 4 5 7]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Pair     meaning     value     input slice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// [0, 7]   full match  &amp;#34;2026-08&amp;#34; s[0:7]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// [0, 4]   year group  &amp;#34;2026&amp;#34;    s[0:4]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// [5, 7]   month group &amp;#34;08&amp;#34;      s[5:7]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// A group that didn&amp;#39;t participate reports -1, -1 for its pair:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;re2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`(?P&amp;lt;year&amp;gt;\d{4})(?:-(?P&amp;lt;month&amp;gt;\d{2}))?`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;re2&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatchIndex&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2026&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// idx2 = [0 4 0 4 -1 -1]  &amp;lt;- month didn&amp;#39;t participate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-submatchindex-contract&#34;&gt;The &lt;code&gt;SubmatchIndex&lt;/code&gt; Contract&lt;/h3&gt;
&lt;p&gt;When using the &lt;code&gt;Index&lt;/code&gt; variants, the returned slice is a flat list of &lt;code&gt;[start, end]&lt;/code&gt; pairs: element &lt;code&gt;0:1&lt;/code&gt; is the whole match, &lt;code&gt;2:3&lt;/code&gt; is the first group, &lt;code&gt;4:5&lt;/code&gt; the second, and so on. This is incredibly useful for slicing out substrings efficiently, or when the &lt;em&gt;positions&lt;/em&gt; of the matches matter (for highlighting, parsing, or logging) rather than the text.&lt;/p&gt;
&lt;p&gt;For example, slicing each pair directly out of the input:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`(\w+)@(\w+)`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Contact: alice@example&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatchIndex&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// idx = [9 22 9 14 15 22]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;full&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]:&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]] &lt;span style=&#34;color:#75715e&#34;&gt;// s[9:22]  -&amp;gt; &amp;#34;alice@example&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]:&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;]] &lt;span style=&#34;color:#75715e&#34;&gt;// s[9:14]  -&amp;gt; &amp;#34;alice&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;]:&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]] &lt;span style=&#34;color:#75715e&#34;&gt;// s[15:22] -&amp;gt; &amp;#34;example&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;4-grammar-review-what-go-supports&#34;&gt;4. Grammar Review: What Go Supports&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s go over the syntax Go supports.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Syntax note:&lt;/strong&gt; Go&amp;rsquo;s regexp uses &lt;strong&gt;RE2 syntax&lt;/strong&gt;, so PCRE-isms like &lt;code&gt;\1&lt;/code&gt; backreferences, lookaround, and atomic/possessive groups do &lt;strong&gt;not&lt;/strong&gt; compile. Anything that relies on them must be rewritten.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Concept&lt;/th&gt;
					&lt;th&gt;Syntax&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
					&lt;th&gt;Example&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Single Characters&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Any character (except newline by default)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;a.c&lt;/code&gt; matches &lt;code&gt;abc&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Character Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[a-z0-9]&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Any character in the set&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[A-Z]&lt;/code&gt; matches capital letters&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Negated Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[^a-z]&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Any character &lt;em&gt;not&lt;/em&gt; in the set&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[^0-9]&lt;/code&gt; matches non-digits&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Perl Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\d&lt;/code&gt;, &lt;code&gt;\w&lt;/code&gt;, &lt;code&gt;\s&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Digits, word characters, whitespace&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\w+&lt;/code&gt; matches a word&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Negated Perl Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\D&lt;/code&gt;, &lt;code&gt;\W&lt;/code&gt;, &lt;code&gt;\S&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Non-digits, non-word, non-whitespace&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\S+&lt;/code&gt; matches visible text&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Anchors&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;^&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;\b&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Start of line, end of line, word boundary (ASCII-only)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;^\w+$&lt;/code&gt; matches exactly one word&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Greedy Quantifiers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;*&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;0+, 1+, or 0–1 of the preceding&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;a*&lt;/code&gt; matches ``, &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;aa&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Lazy Quantifiers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;*?&lt;/code&gt;, &lt;code&gt;+?&lt;/code&gt;, &lt;code&gt;??&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Same, but match the &lt;em&gt;minimum&lt;/em&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;.+?&amp;gt;&lt;/code&gt; matches an HTML tag&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Exact Quantifiers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;{n}&lt;/code&gt;, &lt;code&gt;{n,m}&lt;/code&gt;, &lt;code&gt;{n,}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Exactly &lt;code&gt;n&lt;/code&gt;, between &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt;, or &lt;code&gt;n&lt;/code&gt;+&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\d{3,4}&lt;/code&gt; matches 3 or 4 digits&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Capturing Groups&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(re)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Groups the regex and captures the text&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(abc)+&lt;/code&gt; matches &lt;code&gt;abcabc&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Named Captures&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?P&amp;lt;name&amp;gt;re)&lt;/code&gt; / &lt;code&gt;(?&amp;lt;name&amp;gt;re)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Captures and assigns a name&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?P&amp;lt;year&amp;gt;\d{4})&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Non-Capturing Group&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?:re)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Groups without capturing&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?:abc)+&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Inline Flags&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?i)&lt;/code&gt;, &lt;code&gt;(?m)&lt;/code&gt;, &lt;code&gt;(?s)&lt;/code&gt;, &lt;code&gt;(?U)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Case-insensitive, multi-line, dot-matches-all, ungreedy&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?i)hello&lt;/code&gt; matches &lt;code&gt;HELLO&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A few details worth calling out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Greedy vs. lazy.&lt;/strong&gt; By default quantifiers are greedy - they consume as much as possible while still allowing the overall match. Appending &lt;code&gt;?&lt;/code&gt; makes them lazy - they consume as little as possible. The classic example: &lt;code&gt;&amp;lt;.+&amp;gt;&lt;/code&gt; against &lt;code&gt;&amp;lt;a&amp;gt;&amp;lt;b&amp;gt;&lt;/code&gt; greedily matches the whole string, while &lt;code&gt;&amp;lt;.+?&amp;gt;&lt;/code&gt; matches just &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Named captures.&lt;/strong&gt; Go supports both the Python-style &lt;code&gt;(?P&amp;lt;name&amp;gt;re)&lt;/code&gt; and the &lt;code&gt;.NET&lt;/code&gt;/&lt;code&gt;(?&amp;lt;name&amp;gt;re)&lt;/code&gt; spelling. They can be referenced by name in replacements with &lt;code&gt;${name}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ungreedy flag &lt;code&gt;(?U)&lt;/code&gt;.&lt;/strong&gt; This flips the default so that quantifiers are lazy unless explicitly made greedy with &lt;code&gt;?&lt;/code&gt;. It&amp;rsquo;s the same idea as Python&amp;rsquo;s &lt;code&gt;(?U)&lt;/code&gt; and is easy to forget.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;5-putting-it-together-scam-sms-detection-at-scale&#34;&gt;5. Putting It Together: Scam SMS Detection at Scale&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s pull everything together with a realistic task: a stream of incoming SMS messages that we want to flag as potential scams. A common signal is the presence of contact details - an international phone number, a local number, or a short code like &lt;code&gt;48291&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Start with the individual patterns (each is a separate signal a detection system might care about):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;phoneIntlRe&lt;/span&gt;  = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\+[1-9]\d{0,2}(?:[ .-]?\(?[0-9]{1,4}\)?)?(?:[ .-]?[0-9]{1,4}){2,4}`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;phoneLocalRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\b\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}\b`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;shortCodeRe&lt;/span&gt;  = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\b\d{5,6}\b`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the key design decision. Instead of running these three separately - three full scans per message, or three goroutines per message - combine them into a single alternation. RE2&amp;rsquo;s automaton tracks &lt;strong&gt;all branches simultaneously in one forward pass&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`\+[1-9]\d{0,2}(?:[ .-]?\(?[0-9]{1,4}\)?)?(?:[ .-]?[0-9]{1,4}){2,4}`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|\b\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}\b`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|\b\d{5,6}\b`&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To also know &lt;em&gt;which&lt;/em&gt; signal fired, wrap each branch in a named group and use &lt;code&gt;SubexpNames()&lt;/code&gt; together with &lt;code&gt;FindStringSubmatch&lt;/code&gt; - combining the method-matrix pieces we covered earlier:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`(?P&amp;lt;intl&amp;gt;\+[1-9]\d{0,2}(?:[ .-]?\(?[0-9]{1,4}\)?)?(?:[ .-]?[0-9]{1,4}){2,4})`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|(?P&amp;lt;local&amp;gt;\b\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}\b)`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|(?P&amp;lt;short&amp;gt;\b\d{5,6}\b)`&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;signal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatch&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SubexpNames&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;#34;intl&amp;#34;, &amp;#34;local&amp;#34;, or &amp;#34;short&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now for throughput at scale. Because &lt;code&gt;*regexp.Regexp&lt;/code&gt; is safe for concurrent use, parallelize &lt;strong&gt;across the message stream&lt;/strong&gt; - one worker per CPU core, each running the same combined regex. This scales linearly with cores, without the overhead of spawning a goroutine per pattern per message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worker&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MatchString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;workers&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GOMAXPROCS&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;workers&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worker&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;incomingMessages&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    close(&lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// consume `flagged` concurrently...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Why not just run the three regexes concurrently? Benchmarking both approaches on a synthetic corpus showed the combined regex is just as fast - but with &lt;strong&gt;zero allocations&lt;/strong&gt; instead of thousands, and at most one goroutine per CPU core instead of three per message. It also does less total work: one pass per message instead of three.&lt;/p&gt;
&lt;p&gt;And because the engine is linear-time, this whole pipeline is safe to run against &lt;strong&gt;untrusted SMS content&lt;/strong&gt; - no timeout needed, no ReDoS risk. That&amp;rsquo;s the payoff of the design decisions from section 1.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;regexp&lt;/code&gt; package isn&amp;rsquo;t a weaker version of what Python or JavaScript offer - it&amp;rsquo;s a &lt;em&gt;different trade-off&lt;/em&gt;, and one that&amp;rsquo;s entirely deliberate. Its linear-time guarantee, rooted in Ken Thompson&amp;rsquo;s automaton work and brought to maturity by Russ Cox&amp;rsquo;s RE2, means untrusted input can be run against any pattern without fear of ReDoS.&lt;/p&gt;
&lt;p&gt;The cost is losing backreferences and lookaround. In exchange, the engine&amp;rsquo;s performance is predictable and safe, and the API - once the &lt;code&gt;Find(All)?(String)?(Submatch)?(Index)?&lt;/code&gt; matrix is learned - is completely systematic.&lt;/p&gt;
&lt;p&gt;The next time a Go regex refuses to compile a lookahead, remember: it&amp;rsquo;s not a bug. It&amp;rsquo;s the price of a promise.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;references--examples&#34;&gt;References &amp;amp; Examples&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/regular-expressions/examples&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Runnable examples from this post&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Official Documentation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/regexp&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Go &lt;code&gt;regexp&lt;/code&gt; package documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;History &amp;amp; Engine&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Ken_Thompson&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ken Thompson&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.nokia.com/bell-labs/about/dennis-m-ritchie/qed.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;QED text editor (Bell Labs)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Thompson%27s_construction&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Thompson NFA construction&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/google/re2&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;RE2 (original C++ library)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://swtch.com/~rsc/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Russ Cox&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://swtch.com/~rsc/regexp/regexp1.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;RE2: Regular Expression Matching Can Be Simple And Fast&lt;/a&gt;
 - Russ Cox&amp;rsquo;s definitive series&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Safety &amp;amp; Security&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Regular Expression Denial of Service (ReDoS) - OWASP&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.pcre.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PCRE - Perl Compatible Regular Expressions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Other Engines (Backtracking)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.python.org/3/library/re.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Python &lt;code&gt;re&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/util/regex/package-summary.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Java &lt;code&gt;java.util.regex&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/k-takata/onigmo&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ruby &lt;code&gt;Onigmo&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
  </channel>
</rss>
