空白与换行:点号与 \s 各管什么
语法速览 里 . 与 \s 一笔带过,这页把两者掰开。JS 正则的 . 在没有 s 标志时默认不匹配四个行终止符;而 \s 匹配的是 ECMAScript 的 WhiteSpace 加 LineTerminator 全集,涵盖 NBSP、各种排版空格、全角空格,甚至
BOM。这些字符看不见却真实存在。
1 · 四个行终止符
JS 里的行终止符恰好四个:\n、\r、U+2028(行分隔)与 U+2029(段落分隔)。. 默认跳过它们,开 s 才让 . 吃下换行;它们同时也都属于 \s。常被忘记的是后两个。另外 m 改的是 ^ 与
$ 的含义,不是 .;让 . 跨行的是 s,两者别混。
2 · \s 的完整清单
\s 的成员按宽度排开能看出 thin、en、em 与全角的宽窄差。这张表里每一行的命中都是实时用 /^\s$/u 测出来的。
警示 · 两处反直觉。其一,BOM U+FEFF 被 \s 命中——它在规范里是 ZWNBSP,算 WhiteSpace,所以开头带 BOM 的文本,\s 会把它当空白。其二反过来,零宽空格 U+200B 名字带 space,\s 却不认,它是格式字符 Cf,不在 WhiteSpace
里;U+200C 与 U+200D 同理。
3 · 隐形字符扫描
从别处复制来的文本常混入 NBSP、全角空格与 BOM,肉眼看着是普通空格,却让 ===、trim() 与数字解析全部失灵。把文本粘进来,每个空白或不可见字符都会被标出来。
4 · White_Space 属性与「看不见」的边界
上面那张是 ECMAScript \s 的清单;Unicode 自己另有一个二元属性 White_Space,两份名单高度重合却不相等。而「该被渲染器隐藏」的精确属性又是第三个:Default_Ignorable_Code_Point。下面把常见的隐形字符按用途分组摊开,每行实时测这两个属性。
注 · 几个要记的点。DI 列大多打勾,但有一批 gc=Cf 的活动格式符 DI=No,例如 U+0600 框住后续数字、U+FFF9–U+FFFB 的行间注释——它们不是隐藏自己而是影响排版。盲文空白 U+2800 也
DI=No,属于伪空白:gc 是 So、有真字形,只是画出来是空的,与 HANGUL FILLER 一类是绕过「禁止空名」校验的主力。还有 U+180E 曾经属于 White_Space,Unicode 6.3 起降级为
Cf,老代码若硬把它当空白就会与今天的属性对不上。没有单一属性能一网打尽「看不见」,实务上多用 \p{Cf} 并上 \p{Default_Ignorable_Code_Point},再补 U+2800 之类,或维护显式清单。
5 · 参考文献
- Ecma International. ECMA-262: White Space.
\s前半份名单的规范定义,BOM 属于 WhiteSpace 的出处(表 31 列有U+FEFF <ZWNBSP>)。tc39.es - Ecma International. ECMA-262: Line Terminators. 四个行终止符的规范定义。tc39.es
- Unicode. UAX #44: Unicode Character Database.
White_Space与Default_Ignorable_Code_Point两个属性的定义与差别。unicode.org - Unicode. PropList.txt.
White_Space=Yes的全量清单,与\s对照即见两份名单的差。unicode.org - MDN. 字符类转义.
\s、\d、\w各标志位下的行为速查。developer.mozilla.org - MDN. Wildcard.
.单独一页:默认不匹配行终止符,s标志改变这一点。developer.mozilla.org