[Shift_JIS] JIS 基本漢字 (JIS X 0208) 第1・2水準漢字を表わす正規表現

PHP を使って、ある文字列中に JIS 基本漢字 (JIS X 0208) の第 1・2 水準漢字以外のものが含まれているかどうかの判定を実装したかったのですが、いろいろと苦労した & 結局最悪の実装をしたのでその顛末と途中の成果物をここに記します。

これらのウェブサイトがとても参考になりました。

Unicode と JIS 基本漢字コードではその出現順が異なる

JIS X 0208 (1990) to Unicode 漢字コード表 の 16 区以降を見るとわかる通り、 Unicode と SJIS のコード順は異なります。 よって、UTF-8 の文章に対してよくみる [亜-椀] では、うまく第 1 水準漢字だけにマッチすることはできないのです。

たとえば、 逢:E980A2 (UTF-8)亜:E4BA9C (UTF-8) - 椀:E88595 (UTF-8) の間には収まらない、といった風に。

Unicode で範囲マッチできないなら SJIS でやればいいじゃない

今回の目的を達成するには UTF-8 のまま扱うのはとてもしんどいので、マッチさせるときだけ SJIS にエンコードしてしまいましょう。 Python でやるならこんな感じ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import re

# 第 1 水準漢字(16 - 47 区)にマッチ
regexp_for_JIS_16_TO_47 = re.compile(r'\x88[\x9F-\xFC]|[\x89-\x97][\x40-\xFC]|\x98[\x40-\x9E]')

# 第 2 水準漢字(48 - 84 区)にマッチ
regexp_for_JIS_48_TO_84 = re.compile(r'\x98[\x9F-\xFC]|[\x99-\xE9][\x40-\xFC]|\xEA[\x40-\xA4]')

# SJIS にエンコードしてマッチング
regexp_for_JIS_16_TO_47.match(u"腕".encode('sjis'))

結局 PHP では SJIS コードを指定する正規表現が使えなかった

PHP で正規表現を利用したマッチングといえば preg_match ですが、マルチバイトの文字列を対象とする場合は UTF-8 しか受け付けないとのこと。これでは折角用意した正規表現が使えない…

ならば ereg を使えばよいかというと

この関数は PHP 5.3.0 で 非推奨となりました。 この機能を使用しないことを強く推奨します。

とのこと。結局あきらめて、 第1・2水準漢字すべてを羅列した正規表現 を用意したのでした。これは書くまでもないので割愛。というか思い出したくない。