stringr fixed() in R: Match Literal Strings Without Regex
The stringr::fixed() function wraps a pattern so stringr matches it as a literal string instead of a regular expression. Use it whenever your pattern contains characters like ., *, ?, or ( that you want treated as themselves, not as regex metacharacters.
str_detect(x, fixed(".")) # match literal dot
str_replace(x, fixed("a.b"), "X") # replace literal "a.b"
str_extract(x, fixed("ver1.0")) # extract literal "ver1.0"
str_count(x, fixed("$")) # count literal "$"
str_detect(x, fixed("apple", ignore_case=TRUE)) # case-insensitive literal
str_split(x, fixed("|")) # split on literal pipe
str_locate(x, fixed("(1)")) # locate literal "(1)"Need explanation? Read on for examples and pitfalls.
What fixed() does in one sentence
fixed(pattern, ignore_case = FALSE) returns a pattern wrapper that tells any str_* function to compare bytes verbatim, with no regex parsing. Wrap your needle in fixed() whenever the literal characters in it (., *, +, ?, (, ), [, ], {, }, ^, $, |, \) would otherwise be interpreted by the regex engine.
It is not a matching function on its own. You pass its output to str_detect(), str_replace(), str_extract(), str_count(), str_split(), and similar.
Syntax
fixed(pattern, ignore_case = FALSE). Always pass the result into another str_* function.
Without fixed(), the dot would mean "any single character" and would match "v125" too. With fixed(), the dot is just a dot.
fixed() whenever the pattern is user input or a known literal. Regex parsing of unsanitized input is a frequent silent-bug source: a stray ( or * from user data turns a "did this column contain X?" query into a regex error or false positive.Six common patterns
1. Match a literal dot, dollar, or other metacharacter
. is the most common regex metacharacter and a frequent surprise. fixed(".") matches exactly one dot. The bare pattern "." matches every non-empty string.
2. Replace a literal substring containing parens
Parentheses are regex grouping operators. Without fixed(), you would have to escape them as "\\(1\\)".
3. Case-insensitive literal match
The ignore_case = TRUE argument is the literal-match equivalent of regex(..., ignore_case = TRUE). It uses simple ASCII case folding, not locale rules.
4. Count a literal special character
$ is the regex anchor for end-of-string. fixed("$") counts the literal character.
5. Split on a pipe or other delimiter
| is regex alternation. fixed("|") splits on the literal pipe character with no escaping needed.
6. Use inside dplyr filter
The literal .pdf matches the substring exactly. The bare regex ".pdf" would also match "-pdf" because . is "any character".
fixed() is faster than regex for literal needles, and the speed gap grows with pattern length. stringr uses a Boyer-Moore-style scan for fixed patterns and the full regex engine for everything else. For short patterns the difference is tiny; for long literals or millions of strings, fixed() is the right default.fixed() vs regex() vs coll() vs boundary()
stringr ships four pattern modifiers, and each one trades speed for matching power. Pick by what you need to match:
| Modifier | Use when | Speed | Locale-aware |
|---|---|---|---|
fixed("x") |
Literal byte-by-byte match | Fastest | No |
regex("x") |
Regular expression (default) | Fast | No |
coll("x") |
Accents, ligatures, Turkish i, locale rules | Slowest | Yes |
boundary("word") |
Split or detect word, line, sentence | Fast | Locale-aware boundaries |
Decision rule: start with the default (regex). Switch to fixed() when your pattern contains metacharacters you want literal, or you need a speed boost on big data. Switch to coll() only for human-facing text comparisons where "e" and "é" must match.
fixed(x, ignore_case = TRUE) uses ASCII case rules. It does NOT treat accented letters or non-Latin scripts as case variants. For Unicode-correct case folding, use coll(x, ignore_case = TRUE, locale = "en") instead.Common pitfalls
Pitfall 1: forgetting to wrap when the pattern came from user input. If your pattern is a variable from a CSV or form field, assume it may contain regex metacharacters and wrap with fixed() unless you specifically want regex behavior. Otherwise a single user-supplied ( raises invalid regular expression.
Pitfall 2: using fixed() when you actually want word boundaries. str_detect("pineapple", fixed("apple")) returns TRUE. To match apple as a whole word, use the regex "\\bapple\\b" or boundary("word") plus equality.
fixed() does NOT escape backslashes for you, but it also does not interpret them. fixed("\\d") matches the literal two-character sequence backslash-d, not a digit. If you want digit detection, drop fixed() and use the regex "\\d" directly.Pitfall 3: trying to combine fixed() with regex anchors or character classes. fixed("^apple") matches a literal caret followed by "apple", not "starts with apple". For anchored matches, use regex: str_detect(x, "^apple") or str_starts(x, "apple").
Try it yourself
Try it: Use fixed() to count how many times the literal substring "." appears in each element of c("a.b.c", "no dots", "1.5.0"). Save the counts to ex_dot_counts.
Click to reveal solution
Explanation: fixed(".") tells str_count() to look for a literal dot, not the regex "any character". Without fixed(), every non-empty string would return its full length because . matches any character.
Related stringr functions and modifiers
After fixed(), the modifiers and functions you most often pair it with:
regex(): opt back into regex behaviour with options likeignore_case,multiline,dotallcoll(): locale-sensitive literal match for accents and Unicodeboundary(): match word, line, sentence, or character boundariesstr_detect(): TRUE/FALSE per string for the wrapped patternstr_replace()/str_replace_all(): substitute matched textstr_extract()/str_extract_all(): pull out the matched substring
For multi-pattern lookups, see str_subset() (filter) and str_locate() (position). The full reference lives in the stringr documentation.
FAQ
What is the difference between fixed() and regex() in stringr?
fixed() matches the pattern as a literal sequence of bytes, with no regex interpretation. regex() (the default for plain string patterns) treats characters like ., *, +, ?, (, ) as metacharacters. Use fixed() for speed on literal needles or when your pattern includes regex specials you want treated literally.
Is fixed() faster than regex in R?
Yes, especially for long literal patterns and large input vectors. stringr scans fixed patterns with an algorithm tuned for literal substring search and skips regex compilation. For short patterns and small data, the difference is negligible; for production text pipelines, fixed() can be several times faster.
Can fixed() be case-insensitive in stringr?
Yes. Pass ignore_case = TRUE: fixed("apple", ignore_case = TRUE). The match uses ASCII case folding, so A matches a but é does not match E. For Unicode-correct case folding, use coll(pattern, ignore_case = TRUE, locale = "en") instead.
How do I match a literal dot or special character in stringr?
Wrap the pattern in fixed(): str_detect(x, fixed(".")) matches a literal dot. The alternative is escaping in regex: str_detect(x, "\\."). fixed() is clearer when several special characters appear in the same pattern, like fixed("v1.0.0(beta)").
Does fixed() work with stri_ functions from stringi?
Not directly. fixed() returns a stringr-specific wrapper. The stringi equivalent is the stri_* functions that already accept opts_fixed = list() and opts_regex = list() argument lists, or the lower-level stri_detect_fixed(), stri_replace_all_fixed() family.
Can I use fixed() with vectorized patterns?
Yes, fixed() is vectorized over pattern: str_detect(c("a.b","x*y"), fixed(c(".", "*"))) returns c(TRUE, TRUE). Each element of the input is matched against the corresponding element of the pattern. Lengths must match or one of them must be length one.