Regex to trim whitespace, collapse runs and drop blank lines
Trimming a whole string is a job for the built in string method. Regular expressions earn their place when the trimming has to happen per line or when runs of whitespace need collapsing.
At a glance
- Built in preset
- none, this is one to type in yourself
- Trim both ends
- /^\s+|\s+$/g
- Collapse runs
- /\s+/g replaced with a single space
- Trim each line
- /^[ \t]+|[ \t]+$/gm
- Remove blank lines
- /\n\s*\n/g replaced with one newline
- Simpler for whole strings
- String.prototype.trim, which is faster
In detail
For a plain whole string trim there is no argument: the built in method is shorter, faster and cannot be got wrong. The regex version, /^\s+|\s+$/g, is worth knowing because it is the shape you extend when the requirement grows, and because seeing the alternation makes it obvious why the g flag is required and why both halves are anchored.
Collapsing runs is where a pattern genuinely helps. Replacing every /\s+/ with a single space flattens tabs, repeated spaces and line breaks into one separator, which is exactly right for a search index and exactly wrong for a document, because paragraph structure disappears with it. When the line structure has to survive, collapse [ \t]+ instead and leave the terminators alone.
Per line trimming is the case that actually needs the m flag. Anchoring with ^ and $ under m applies the trim at every line boundary, and using [ \t] rather than \s is what stops the pattern eating the line terminators themselves and joining the lines together.
Removing blank lines is easier expressed as a replacement between terminators than as an anchored pattern. Replacing /\n\s*\n/g with a single newline collapses any run of empty or whitespace only lines down to one break, and it leaves a single blank line at the start or end of the text alone, which is usually what you want.
Examples
" a b ".replace(/^\s+|\s+$/g, ""); // "a b"
"a b\n\nc".replace(/\s+/g, " "); // "a b c"
" a \n b ".replace(/^[ \t]+|[ \t]+$/gm, ""); // "a\nb"
"a\n\n\nb".replace(/\n\s*\n/g, "\n"); // "a\nb"/\s/.test("\u00a0"); // true, a no break space is trimmed
/\s/.test("\u200b"); // false, a zero width space is not
"a\u200bb".replace(/\s+/g, " "); // "a\u200bb", unchangedA zero width space is invisible, is not whitespace as far as \s is concerned, and makes two identical looking values compare unequal.
Things that catch people out
- Collapsing on /\s+/ flattens line breaks too, so a document loses its paragraph structure. Use [ \t]+ when the lines have to survive.
- The zero width space U+200B is not matched by \s, so it survives every one of these patterns and keeps breaking equality checks.
- Per line trimming needs both the g and m flags. With g alone the pattern only trims the two ends of the whole string.
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 →\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.
\t: matching tabs in TSV and indented text
\t matches the horizontal tab. Splitting a tab separated row on \s+ instead destroys every empty field, and JavaScript has no \h shorthand.
\r: carriage returns, CRLF and stray line endings
\r matches the carriage return that Windows text puts before every line feed. It is also a line terminator for ^ and $, which not every engine agrees with.
Regex for HTML tags: what the preset matches and what breaks it
The tag preset is fine for finding tags in a known snippet and wrong for parsing a document. A greater than sign inside an attribute value is all it takes.
Regex for numbers: integers, decimals and negative signs
The integer preset splits 3.14 into two matches and the float preset ignores whole numbers. Here is the combined pattern and what it still leaves out.
Regex to extract the text between two delimiters
A lazy quantifier is the usual answer and a negated character class is the better one. Neither can handle nesting, and that limit is worth knowing early.
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