Unicode 正規化と文字種判定

この処理は、 もともと、Web page が英語なのかどうかを判定したいという目的があるのだが、 実際にこのメソッドで処理したら、 例えば、見た感じは全部英語っぽいのだが、 いわゆる全角空白が使われている、 というページが出てくる。 どう見ても英語なのだが、 これを日本語ページという判定にしていいのか?

あと、ABC は日本語でないとして、「ABC」(全角)はどっちなんだ、 みたいなのも。 中身は全部英語なのだがなぜか「無題ドキュメント」というタイトルのページもある。 「MS ゴシック」というフォント名が指定されているとか、 なかなか奥が深い。

フォントの指定と「無題ドキュメント」の問題はがんばって HTML を parse する*1しかないと思うが、いわゆる全角アルファベット、全角空白の問題は正規化してしまえば解決する問題だと思う。
Java SE 6 以降であれば java.text.Normalizer を使ってこんなメソッドを用意すればよい。

    public static boolean isJapanaese(String str) {
        Pattern pattern = Pattern.compile("[\\p{InHiragana}\\p{InKatakana}\\p{InCJKUnifiedIdeographs}\\p{InCJKSymbolsAndPuctuation}]+");
        String normalized = Normalizer.normalize(str, Normalizer.Form.NFKC);
        Matcher matcher = pattern.matcher(normalized);
        return matcher.find();
    }

前のエントリでは安易に Character.UnicodeBlock を使えばいい、みたいなことを書いたが、よく考えれば java.util.regex.Pattern は Unicode Block をサポートしているわけで、こちらの方がシンプルに済む。
あと、厳密に考えればCJK統合漢字拡張A、B も追加したほうがいいかもしれないが、日本語の文章判定と考えればなくても特に問題ないだろう。というか、普通、ひらがなを使わずに現代日本語の文章を書くのは無理なので、\\p{InHiragana} だけでも結構実用になるかもしれない。まぁ、サイトマップのページとかではまりそうだが。
ところで。

気分的にハングルとか中国語で誤判定しそうな気がするが、 ソレはソレ、コレはコレ、ということで今回は気にしない。

ハングルはまったく別の Unicode Block に納められているので、問題ないはずだ。韓国語の文章で漢字や、句読点の類がどう使われるかはよく知らないが、ハングルを誤認識することはないだろう。
念のため書いておくと、ハングルとは字種の名前であって言語そのものの名前ではない*2。日本語でいうひらがなみたいなものだ。割と誤解している人は多いが。

*1:TagSoupなどが使えるかも

*2:日本では政治的な事情によりハングルと呼称することもあるらしい