Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

\sが完全には空白文字を網羅できていなかった件

「空白文字」が世の中に何種類あるかご存じですか?半角スペース、全角スペース、タブ、改行くらいは分かると思いますが、実は世の中にはもっと空白文字があります。なんと空白文字だけで30文字以上もあります。これだけある空白文字を、/\s/は果たして網羅できているのでしょうか?今回はこれについて調べてみました。

'\s'にマッチするスペース文字の一覧

2. スペースは" "だけじゃない的な話

ここのページに書いてあるスペース文字について、\sにマッチするか検証してみま した。

結論から書くと、\sは全てを網羅していませんでした。 青くなっている方が\sにマッチした文字、赤くなっている方がマッチしなかった文 字です。

名称文字
FILE SEPARATOR[]
GROUP SEPARATOR[]
RECORD SEPARATOR[]
UNIT SEPARATOR[]
HANGUL JUNGSEONG A-EU[ᆣ]
HANGUL JUNGSEONG YA-U[ᆤ]
HANGUL JUNGSEONG YEO-YA[ᆥ]
HANGUL JUNGSEONG O-YA[ᆦ]
HANGUL JUNGSEONG O-YAE[ᆧ]
MONGOLIAN VOWEL SEPARATOR[᠎]
ゼロ幅空白[​]
ワード接合子[⁠]
HANGUL FILLER[ㅤ]
水平タブ (HT)[ ]
改行 (LF)[ ]
垂直タブ (VT)[ ]
フォームフィード (FF)[ ]
復帰キャリッジ・リターン (CR)[ ]
スペース[ ]
ノーブレークスペース[ ]
OGHAM SPACE MARK[ ]
EN QUAD[ ]
EM QUAD[ ]
EN SPACE[ ]
EM SPACE[ ]
THREE-PER-EM SPACE[ ]
FOUR-PER-EM SPACE[ ]
SIX-PER-EM SPACE[ ]
FIGURE SPACE[ ]
PUNCTUATION SPACE[ ]
THIN SPACE[ ]
HAIR SPACE[ ]
NARROW NO-BREAK SPACE[ ]
MEDIUM MATHEMATICAL SPACE[ ]
和字間隔[ ]
ゼロ幅のノーブレークスペース[]

ゼロ幅文字

名称文字
結合書記素接合子[͏]
ゼロ幅空白[​]
ゼロ幅非接合子[‌]
ゼロ幅接合子[‍]
記述方向制御(左から右へ)[‎]
記述方向制御(右から左へ)[‏]
LRE[‪]
RLE[‫]
PDF[‬]
LRO[‭]
RLO([[になってますが誤字ではありません)[‮]
関数適用[⁡]
不可視の乗算記号[⁢]
不可視の区切り文字[⁣]
行区切り文字[
]
段落区切り文字[
]
ゼロ幅のノーブレークスペース[]

マッチしない空白文字が思っていた以上にありますね。

仕様書を見てみる

仕様書を読んで確認をしてみます。

ECMA-262 8th Edition(ES2017)には\sについて次のような記述があります。

Return the set of characters containing the characters that are on the right‐hand side of the WhiteSpace or LineTerminator productions.

つまり、「\sは空白文字、あるいは行末文字にマッチする」ということです。

ECMAScriptで空白文字、行末文字は次のように定められています。

空白文字

  • U+0009(水平タブ)
  • U+000B(垂直タブ)
  • U+000C(フォームフィード)
  • U+0020(普通のスペース)
  • U+00A0(ノーブレークスペース)
  • U+FEFF(ゼロ幅のノーブレークスペース)
  • その他のUnicodeのSpace_Separator

その他のUnicodeのSpace_Separatorというのは次のとおりです(参考: https://www.compart.com/en/unicode/category/Zs)

  • U+1680(オガム文字のスペース)
  • U+2000(n幅の四角形)
  • U+2001(m幅の四角形)
  • U+2002(n字幅の空白)
  • U+2003(m字幅の空白)
  • U+2004(1/3m幅の空白)
  • U+2005(1/4m幅の空白)
  • U+2006(1/6m幅の空白)
  • U+2007(数字用空白)
  • U+2008(句読点用空白)
  • U+2009(狭い空白)
  • U+200A(非常に狭い空白)
  • U+202F(幅の狭いノーブレークスペース)
  • U+205F(中くらいの大きさの数学用空白)
  • U+3000(全角スペース)

行末文字

  • U+000A(改行)
  • U+000D(復帰キャリッジ・リターン)
  • U+2028(行区切り文字)
  • U+2029(段落区切り文字)

'\s'と等価な正規表現とは?

つまりまとめると、\s は次の正規表現と同じです。

// /\s/
/[\u0009\u000a\u000b\u000c\u000d\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/

終わりに

というわけで、「\sは世の中のすべての空白文字を網羅しているわけではない」と分かりました。

半角スペース・全角スペース・タブに対応していれば十分なケースが多いですが、本当にすべての空白文字に対応しなければいけない場面は \s では事足りないことは覚えておきましょう。

(空白文字に対応する場面というのは、例えば入力必須のユーザー名などです。そこで空白文字が通ってしまうと、あたかもユーザー名が空のように表示されてしまいます)