[^abc]: negated character sets that quietly cross newlines
[^abc] matches exactly one character that is not in the listed set. Because line terminators are not in the set either, a negated class crosses newlines without the s flag.
At a glance
- Syntax
- [^abc]
- Matches
- one character that is not in the set
- Line terminators
- matched, unless you exclude them explicitly
- The caret
- negates only in first position, literal anywhere else
- Scope
- one character, never a sequence
- Why it is fast
- a negated class to a known terminator does not backtrack the way .*? does
In detail
A negated class is the workhorse of delimited scanning. Matching a quoted string with /"[^"]*"/ is both clearer and cheaper than the lazy dot version, because the class simply consumes until it hits a quote and never has to reconsider. Any time you know what the terminator is, this is the shape to reach for.
The consequence people miss is that a newline is not the terminator either. Running /"[^"]*"/ over a string with a line break between the quotes matches the whole thing, line break included. That is unrelated to the s flag, which only ever touches the dot, so turning s on to change this behaviour does nothing at all.
If crossing lines is wrong for your input, say so in the class. [^"\n] excludes both the quote and the line feed, and the pattern then stops at the end of the line where a reader would expect it to. Adding the terminator to the class is the fix, not adding a flag.
Two smaller points. The caret only negates in first position, so [a^b] is a set containing a caret rather than a negation of anything. And negation is per character, so [^abc] does not mean not the string abc; it means one character that is not a, b or c, which is a very different claim.
Examples
/"[^"]*"/.exec('"one\ntwo"')[0]; // '"one\ntwo"'
/"[^"\n]*"/.exec('"one\ntwo"'); // null
const m = /[^abc]/.exec("aabxc");
m[0]; // "x"
m.index; // 3"a^b".match(/[a^]/g); // ["a", "^"]
/[^a]/.test("a"); // false, this one negatesThings that catch people out
- A negated class matches line terminators, so a quoted string pattern silently swallows a line break. Add \n to the class rather than reaching for a flag.
- [^abc] means one character other than those three. It is not a way to say the text is not abc, and using it that way accepts almost everything.
- The caret only negates in first position, so [a^b] matches a literal caret and accepts input the pattern was written to reject.
Try it: Regex Tester
Type a pattern and a test string, watch every match highlight as you go, read a plain English breakdown of each token, and check the numbered and named groups it captured.
Regex Tester
LOCAL · Browser-OnlyTest and debug regular expressions with live matching and highlights
Related Regex syntax
All regex syntax →[abc]: character sets and what loses its meaning inside
A bracket set matches one character from a list. Most metacharacters go literal inside it, and only four keep any special meaning at all.
The dot: any character except a line terminator
What the dot matches by default, the four characters it skips, how the u and s flags change it, and why it needs no escape inside a character class.
(?!...): negative lookahead for exclusion rules
A negative lookahead succeeds when the pattern inside it fails. The classic bug is a greedy quantifier that backtracks until the assertion passes.
[a-z] ranges: code point order and the A-z bug
Ranges inside a character class run by code point, which is why [A-z] quietly includes six punctuation characters and [a-Z] is a syntax error.
\p{...}: Unicode property escapes, and the flag they need
Property escapes match by Unicode category or script instead of by code point range. Without the u flag they compile into something else entirely.
\b: word boundaries, underscores and accented letters
\b is a zero width assertion defined entirely in terms of \w, which is why user_name has no internal boundary and café has none at its end.
Tools for this
- Regex Tester Free online regex tester - test and debug regular expressions with live matching and highlights
- Regex Playground Regex playground with live match highlighting, named groups, find and replace, and shareable links