What does regexp.QuoteMeta do to a string before you concatenate it into a Go pattern?
answer
- their text, your pattern
- a dot is not a dot
- backslashes in front of the specials
- unbalanced bracket breaks compilation
- if it is all literal, use strings
basics
~20 sregexp.QuoteMeta returns a copy of the string with every regular-expression metacharacter backslash-escaped. Text such as v1.2(beta) then matches literally instead of being read as a pattern, and it can no longer break the surrounding pattern's syntax.
solid answer
~50 s`regexp.QuoteMeta(s string) string` escapes the characters that mean something to the regexp parser — `\ . + * ? ( ) | [ ] { } ^ $` — so the result matches the original text literally. You use it when part of a pattern is data: a search term, a hostname, a version string, an operator-supplied word you want to find inside a larger pattern you control. Without it two things go wrong: a `.` or `+` silently changes what matches, and an unbalanced `(` or `[` makes `regexp.Compile` fail outright. You escape the *fragment*, not the whole pattern — the anchors, groups and character classes around it are still yours. Compile the assembled pattern once per distinct term and reuse it, rather than rebuilding it per line. And if the whole thing is literal, skip `regexp` entirely and use `strings.Contains`.
code
go · 4 lines// term is operator-supplied text such as `v1.2(beta)`.
func lineFilter(term string) (*regexp.Regexp, error) {
return regexp.Compile(`^\[warn\] .*` + regexp.QuoteMeta(term))
}go deeper
Know that data spliced into a pattern must be escaped with regexp.QuoteMeta, and that a dot or a plus in a user's text otherwise changes what matches.
Explain which characters are metacharacters, why an unbalanced bracket makes compilation fail, and why you escape only the data fragment rather than the whole pattern.
Show where the compile belongs once terms are dynamic — once per distinct term, cached if terms repeat — and be willing to argue that a fully literal search should use the strings package instead.
Set the boundary for the codebase: which inputs may contribute pattern syntax at all, versus which are always quoted as data, so no future caller has to rediscover the rule.
## The problem QuoteMeta solves A regular expression is a small language, and string concatenation does not respect it. The moment you write ```go pat := `^\[warn\] ` + term ``` where `term` came from a user, a config file, a database row or a CLI flag, that user is writing part of your pattern. Two distinct failures follow. **Silent meaning changes.** If `term` is `v1.2`, the `.` matches any character, so `v1x2` matches too. If it is `a+b`, the `+` is a repetition operator applied to `a`. If it is `sales|hr`, the alternation now spans your whole pattern, because `|` has very low precedence — `^\[warn\] sales` or `hr` anywhere. Nothing errors; the results are just quietly wrong. **Compile failures.** If the text contains an unbalanced `(` or `[`, or a trailing `\`, `regexp.Compile` returns an error and your code takes the error path for what is, from the user's point of view, an ordinary search term. ## What QuoteMeta does ```go func QuoteMeta(s string) string ``` It returns a copy of `s` in which every character that has special meaning in a regular expression is preceded by a backslash. The metacharacters are `\ . + * ? ( ) | [ ] { } ^ $`. Ordinary letters, digits and spaces are untouched. So: ```go regexp.QuoteMeta(`v1.2(beta)`) // v1\.2\(beta\) ``` The escaped result is guaranteed to be a valid pattern that matches exactly the original characters — it removes the pattern language from that fragment entirely. ## Escape the fragment, not the pattern The common mistake is to quote the whole assembled pattern, which defeats the point: your own anchors and groups become literal too. The shape is always "my pattern, with their text escaped inside it": ```go func lineFilter(term string) (*regexp.Regexp, error) { return regexp.Compile(`^\[warn\] .*` + regexp.QuoteMeta(term)) } ``` Here the anchor, the literal `[warn]` prefix (escaped by hand because `[` is a metacharacter in *my* text too) and the `.*` are mine and stay live; only `term` is neutralised. ## Compilation still has to be hoisted Quoting does not change the economics. The assembled pattern still has to be compiled, and compiling is much more expensive than matching. Compile **once per distinct term** — when the search is issued, when the config loads, when a new filter is registered — and keep the `*regexp.Regexp` for as long as that term is in use. Rebuilding the string and recompiling it for every line you scan is the same waste as any other per-item compile, and the string concatenation adds to it. If terms arrive continuously and each is used many times, a small bounded cache keyed by the term text is the usual arrangement. If each term is used once, you have not saved anything by caching and the straightforward compile-then-match is fine. ## When you should not be using regexp at all If a quoted term is the *entire* pattern, you have written a regular expression that matches a fixed string — which is exactly what the `strings` package does, faster and more clearly: - `strings.Contains(line, term)` for a substring; - `strings.HasPrefix` / `strings.HasSuffix` for anchored ends; - `strings.EqualFold` when you want a case-insensitive whole-string comparison. Reach for `regexp` when you actually need the pattern language: alternation, repetition, character classes, capture groups. `QuoteMeta` is for the case where you need *some* of that, and one piece of the pattern happens to be data. ## Two details worth knowing - **A quoted fragment always compiles.** Since `QuoteMeta`'s output is a plain literal, it cannot make the pattern malformed. Your surrounding pattern still can, so if any part of the assembled pattern comes from you and is not a proven-good literal, keep using `regexp.Compile` and handle the error. - **Quoting is not anchoring.** `QuoteMeta` makes the text literal; it does not decide *where* the text must appear. If you want a whole-field match, you still add `^` and `$` yourself. ## What a weak answer sounds like "`regexp.Compile` escapes its input" — it does not; it parses it. "`QuoteMeta` matches the string" — it returns a string, it does not match anything. "Quoting makes user patterns safe" — it makes user *text* literal, which is a different thing from letting users write real patterns.
- If the entire pattern is a quoted literal term, is regexp still the right tool?Usually not. A pattern with no pattern features left in it is a fixed-string search, so `strings.Contains`, `strings.HasPrefix` or `strings.HasSuffix` does the same job with no compilation step and less code. Keep `regexp` for when you need alternation, repetition, classes or capture groups around the literal.
- Can the assembled pattern still fail to compile after you quote the user's fragment?Yes, but not because of their fragment — quoted output is always a valid literal. If any other part of the pattern is assembled rather than a proven literal, `regexp.Compile` can still return an error, so keep checking it. Only a pattern that is entirely a source literal justifies `regexp.MustCompile`.
- A search box drives this, and each term is scanned across a million lines. Where does the compile belong?Once per search, not once per line: build the quoted pattern and compile it when the query arrives, then match the one `*regexp.Regexp` against every line. If the same terms recur, keep a bounded cache keyed by the term text so repeat searches skip compilation too.
saying these in an interview costs you the question
- Believing regexp.Compile escapes its input automatically
- Quoting the whole pattern instead of the data fragment
- Thinking QuoteMeta performs the match itself
- Assuming quoting also anchors the match
- Rebuilding and recompiling the quoted pattern per line