\W: non word characters, and the underscore it will not match
\W matches any character that is not an ASCII letter, an ASCII digit or an underscore. The underscore is the one people expect it to match and it never does.
At a glance
- Syntax
- \W
- Equivalent to
- [^A-Za-z0-9_]
- Underscore
- never matched, it is a word character
- Accented letters
- always matched, é and ñ are not word characters
- Positive form
- \w
- Common use
- split(/\W+/) to break prose into rough tokens
In detail
As a complement, \W matches punctuation, whitespace, symbols and every character outside the ASCII letter and digit ranges. Splitting a sentence on /\W+/ therefore gives a serviceable rough tokenizer, and it is a common first step before counting words or building a naive index.
The underscore is the surprise. Because \w includes it, \W excludes it, so replacing every \W in "snake_case" leaves the string completely untouched. Anyone writing a sanitiser that strips punctuation from an identifier discovers this the first time an underscore survives, and anyone splitting camel or snake case on \W discovers it a good deal later.
The second surprise runs the other way. Accented letters are not word characters, so \W matches them. Running /\W/ over "naïve" finds the dotted i at index two, which means a sanitiser built on \W will strip diacritics out of names while leaving underscores alone. That combination is almost never what anyone intended.
When the real intent is punctuation and whitespace, write the class you mean. [^\p{L}\p{N}] with the u flag matches anything that is neither a letter nor a number in any script, and it treats the underscore and the accented e the way a reader would expect.
Examples
"hello_world, again".split(/\W+/); // ["hello_world", "again"]
"snake_case".replace(/\W/g, "-"); // "snake_case", unchangedconst m = /\W/.exec("naïve");
m[0]; // "ï"
m.index; // 2Things that catch people out
- \W does not match an underscore, so a sanitiser built on it leaves underscores in place while stripping other punctuation.
- \W does match accented letters, so the same sanitiser strips the diacritics out of names it should have preserved.
- Splitting on /\W+/ leaves an empty string at each end when the input starts or finishes with punctuation or whitespace, so " a b " comes back as four elements, two of them empty.
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 →\w: the word character class, underscore included
\w is exactly [A-Za-z0-9_] in JavaScript. That includes the underscore and excludes every accented letter, which is where most \w bugs come from.
[^abc]: negated character sets that quietly cross newlines
A negated class matches one character that is not in the set, including line terminators. That is why a quoted string pattern runs across lines.
Regex to trim whitespace, collapse runs and drop blank lines
There is no preset for this one. Four short patterns cover trimming, collapsing, per line trimming and removing blank lines, and each has a different failure.
\s: every whitespace character it actually matches
The full list behind \s in JavaScript, including the no break space and the byte order mark, plus the one invisible character it deliberately skips.
\S: non whitespace, and the [\s\S] any character trick
\S is the complement of \s, which makes it a blank check in one character. Paired with \s it also gives the standard match anything class.
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.
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