Perl CGI でフォームからの絵文字入力を制限する方法

絵文字にマッチさせる正規表現

絵文字にマッチさせる Perl 正規表現サンプルコード(バグ有り)

#絵文字コード正規表現
my $docomo = '(?:(?:\xf8[\x9f-\xfc])|(?:\xf9[\x40-\x49\x50-\x52\x55-\x57\x5b-\x5e\x72-\xfb]))';
my $ez = '(?:(?:[\xf3\xf6\xf7][\x40-\xfc])|(?:\xf4[\x40-\x8d]))';
my $voda = '\x1b\x24[GEFOPQ][\x21-\x7a]*\x0f'; #少々簡略

if ($str =~ m/(?:$docomo|$ez|$voda)/){
    print "emoji matched";
} else {
    print "emoji not matched";
}

上記のように書いてしまうと、絵文字がある場合はマッチしますが、下記のように2バイトの「後半+前半」が絵文字コードの並び順と一致する場合もマッチしてしまいます。

間違ってマッチする例 「程度」

程度
│└─┐
↓  ↓
92F6 9378
 ↓ ↓
  F693 という並びが EZ Webの絵文字範囲と一致

絵文字にマッチさせる正規表現(修正版)

この問題を回避するためには、文字列の最初から順に他の文字にマッチするかどうかをチェックしていきます。

#Shift_JIS体系におけるコード
my $ascii = '[\x00-\x7f]'; #ASCIIと制御文字
my $two_bytes = '[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]'; #漢字
my $h_katakana = '[\xa0-\xdf]'; # 半角カタカナ

#絵文字コード正規表現
my $docomo = '(?:(?:\xf8[\x9f-\xfc])|(?:\xf9[\x40-\x49\x50-\x52\x55-\x57\x5b-\x5e\x72-\xfb]))';
my $ez = '(?:(?:[\xf3\xf6\xf7][\x40-\xfc])|(?:\xf4[\x40-\x8d]))';
my $voda = '\x1b\x24[GEFOPQ][\x21-\x7a]*\x0f'; #少々簡略

if ($str =~ m/^(?:$ascii|$two_bytes|$h_katakana)*?(?:$docomo|$ez|$voda)/){
    print "emoji matched";
} else {
    print "emoji not matched";
}

普通の文字を表すコード列は、「(?:$ascii|$two_bytes|$h_katakana)*?」の範囲に入って、絵文字のマッチ対象からは除かれます。

なお、「*?」は「0以上の繰り返しのうち最短のもの」と合致します(Perl 5以上で使用可)。
Vodafone の絵文字を構成する文字は全て「$ascii」の構成文字に含まれてしまいますが、絵文字正規表現に合致するパターンがあれば、絵文字のパターンの方にマッチします。