制御文字を表す正規表現

2011年10月5日水曜日

perl セキュリティ その他IT 正規表現

t f B! P L

決まった型のないデータ(例えば住所とか文章とか)を受け取る場合の入力値検証では、制御文字が含まれていないかというチェックを行う。 制御文字とは、16進表記で 00 ~ 1F と 7F の文字で、通常画面上には表示されない文字通り機器を制御するためのコード。 それぞれのコードがどのような意味かは以下のリンクを参照。
Wikipedia の ASCII 制御文字についての記事
許可する可能性のあるものだけ抜粋すると、タブ 09、改行 0A、復帰 0D。 住所などの単一行入力ではいずれも許可する必要なし。 文章であれば改行・復帰は許可する必要がある。タブを許可するかどうかは要件次第。

制御文字全てにマッチする正規表現 [\x00-\x1F\x7F]
タブ・改行・復帰以外の制御文字にマッチする正規表現 [\x00-\x08\x0B\x0C\x0E-\x1F\x7F]

例えば perl ならこんな感じで使う。

if ($freetext =~ /[\x00-\x1F\x7F]/) {
 print "制御文字が含まれています。\n";
 exit;
}

ここで注意。上記は『制御文字があったらはじく』例で、$freetext の末尾に改行があったとしても正常に検出してくれる。 ただし、逆に『制御文字以外で構成されていればOK』というコードとして以下のように書いた場合、末尾の改行は通過してしまう。

if ($freetext =~ /^[^\x00-\x1F\x7F]+$/) {
 print "OK\n";
}

これは perl の $ の仕様なので、厳密に判定するには ^$ ではなく \A\z を使えばよい。 以下の例であれば末尾の改行も正常に検出される。

if ($freetext =~ /\A[^\x00-\x1F\x7F]+\z/) {
 print "OK\n";
}

ちなみに上記の正規表現は JIS(ISO-2022-JP) では使えない。 JIS は文字種の切り替え時に ESC が出現するのでそれにひっかかってしまう。 改行などと同じように除外してやる方法もあるが、素直に EUC-JP か UTF-8 に変換してチェックしたほうが良い。
また、UTF-8 なら(?) \P{Cc} で制御文字以外を表せるらしいがよくわかってない。

メモ:POSIX 文字クラスの場合
制御文字 [[:cntrl:]]
制御文字以外 [[:^cntrl:]]
制御文字以外(タブ・改行・復帰は許す)  [[:^cntrl:]\t\n\r]

参考:日本語文字コード

QooQ