漢字にマッチする JavaScript の正規表現パターン2015年12月31日 23時03分

たまに漢字にマッチする正規表現パターンを書きたいときがあります。Perl の正規表現だと Unicode のスクリプト名を使って \p{Han} で漢字にマッチさせられるのですが、JavaScript ではそうはいきません。JavaScript の正規表現には以下のふたつの問題があります。

  1. Unicode スクリプト名の指定 (\p{...}) に対応していない。
  2. そもそも Unicode の符号位置に対してマッチさせられない (UTF-16 における符号単位に対するマッチになる)。

とはいえ、解決不能な問題というわけでもないので、Perl の \p{Han} を JavaScript に移植してみましょう。\p{Han} の範囲は以下のコマンドで参照できます。

perl -MUnicode::UCD -MData::Dumper -E 'say Dumper Unicode::UCD::charscript("Han");'

Perl 5.20.2 (Unicode 6.3.0) では以下の範囲が含まれるとわかりました。

  • U+2E80 - U+2E99
  • U+2E9B - U+2EF3
  • U+2F00 - U+2FD5
  • U+3005 - U+3005
  • U+3007 - U+3007
  • U+3021 - U+3029
  • U+3038 - U+303B
  • U+3400 - U+4DB5
  • U+4E00 - U+9FCC
  • U+F900 - U+FA6D
  • U+FA70 - U+FAD9
  • U+20000 - U+2A6D6 (\uD840\uDC00 - \uD869\uDED6)
  • U+2A700 - U+2B734 (\uD869\uDF00 - \uD86D\uDF34)
  • U+2B740 - U+2B81D (\uD86D\uDF40 - \uD86E\uDC1D)
  • U+2F800 - U+2FA1D (\uD87E\uDC00 - \uD87E\uDE1D)

サロゲートペアが [\uD800-\uDBFF][\uDC00-\uDFFF] であることを踏まえると、BMP 外の範囲はそれぞれ以下の部分的な範囲に展開できます。

  • \uD840\uDC00 - \uD869\uDED6
    • [\uD840-\uD868][\uDC00-\uDFFF]
    • \uD869[\uDC00-\uDED6]
  • \uD869\uDF00 - \uD86D\uDF34
    • \uD869[\uDF00-\uDFFF]
    • [\uD86A-\uD86C][\uDC00-\uDFFF]
    • \uD86D[\uDC00-\uDF34]
  • \uD86D\uDF40 - \uD86E\uDC1D
    • \uD86D[\uDF40-\uDFFF]
    • \uD86E[\uDC00-\uDC1D]
  • \uD87E\uDC00 - \uD87E\uDE1D
    • \uD87E[\uDC00-\uDE1D]

これらを整理して組み合わせると、最終的に以下のパターンが得られます。

/(?:[\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u3005\u3007\u3021-\u3029\u3038-\u303B\u3400-\u4DB5\u4E00-\u9FCC\uF900-\uFA6D\uFA70-\uFAD9]|[\uD840-\uD868][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|[\uD86A-\uD86C][\uDC00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D])/

というわけで「漢字 1 文字にマッチする JavaScript の正規表現パターン」でした。よいお年を。