結合文字列をUnicode正規化で合成する方法の危険性 では、結合文字列を解消する方法としてNFCを適用することの危険性を説明しました。それではどうしたらいいのかをここで考えてみます。
考察
結合文字列を解消する現実的な方法は「Composition Exclusionを処理対象から除いてNFCを適用する」だと思います。そこでComposition Exclusionを正規表現にしてみたのがこちら。
これをもとにしてhappyscriptさんが書いてくれたPerlのスクリプトがこちら。
safetyNFC.pl
#!/usr/bin/perl
use strict;
use Unicode::Normalize;
use utf8; #-ソースがUTF8だという宣言
use Encode;
binmode STDOUT, ":utf8"; #-画面に出力したい文字コード
binmode STDERR, ":utf8"; #-エラー出力に使いたい文字コード
binmode STDIN, ":utf8"; #-標準入力から入ってくる文字コード
my $Target;
my $myReg = '[^\x{0340}\x{0341}\x{0343}\x{0344}\x{0374}\x{037E}\x{0387}\x{0958}-\x{095F}\x{09DC}\x{09DD}\x{09DF}\x{0A33}\x{0A36}\x{0A59}-\x{0A5B}\x{0A5E}\x{0B5C}\x{0B5D}\x{0F43}\x{0F4D}\x{0F52}\x{0F57}\x{0F5C}\x{0F69}\x{0F73}\x{0F75}\x{0F76}\x{0F78}\x{0F81}\x{0F93}\x{0F9D}\x{0FA2}\x{0FA7}\x{0FAC}\x{0FB9}\x{1F71}\x{1F73}\x{1F75}\x{1F77}\x{1F79}\x{1F7B}\x{1F7D}\x{1FBB}\x{1FBE}\x{1FC9}\x{1FCB}\x{1FD3}\x{1FDB}\x{1FE3}\x{1FEB}\x{1FEE}\x{1FEF}\x{1FF9}\x{1FFB}\x{1FFD}\x{2000}\x{2001}\x{2126}\x{212A}\x{212B}\x{2329}\x{232A}\x{2ADC}\x{F900}-\x{FAFF}\x{FB1D}\x{FB1F}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}\x{FB41}\x{FB43}\x{FB44}\x{FB46}-\x{FB4E}\x{1D15E}-\x{1D164}\x{1D1BB}-\x{1D1C0}\x{2F800}-\x{2FA1F}]+';
if ($#ARGV > -1) {
$Target = decode('utf8',$ARGV[0]);
} else {
while (<STDIN>) {
$Target .= $_;
}
}
$Target =~ s/($myReg)/NFC($1)/eg;
print $Target;
他の言語にも応用できると思うのですが、どうでしょうか。
- コメントでUnicodeプロパティの正規表現パターンを教えてもらいました。Perlはここが充実しているのでいいですね~