概要

Unicodeには「ここからここは平仮名の領域」「ここからここは漢字の領域」のように文字種に応じてブロックが決められている。

それらを利用すれば解析対象の文字列が「何語で書かれているか」をある程度判定できたり、エンコードがどれが一番確からしいか確認できたりする、かもしれない。

サンプルコードはJava1.6を使用。

@CretedDate 2010/02/26

JavaのUnicodeBlockによる平仮名・カタカナ・漢字の判定例

JavaのUnicodeBlockを使用すると、対象の文字列が平仮名であるかなどが判定できます。実行する前にjava.text.Normalizer.normalize使ってNFKCで正規化しておくと紛れが減るかもしれません。

// 平仮名判定(UnicodeBlock.HIRAGAN)
System.out.println( UnicodeBlock.of( 'あ' ) == UnicodeBlock.HIRAGANA );
    // => true
System.out.println( UnicodeBlock.of( 'ア' ) == UnicodeBlock.HIRAGANA );
    // => false

// カタカナ判定(UnicodeBlock.KATAKANA)
System.out.println( UnicodeBlock.of( 'ア' ) == UnicodeBlock.KATAKANA );
    // => true
System.out.println( UnicodeBlock.of( 'あ' ) == UnicodeBlock.KATAKANA );
    // => false

// 漢字判定(UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS)
System.out.println( UnicodeBlock.of( '言' ) == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS );
    // => true
System.out.println( UnicodeBlock.of( 'ω' ) == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS );
    // => false

Javaの正規表現を使った平仮名・カタカナ・漢字の判定

Perlにも似た表現があったり、Rubyは1.9から可能だったりするので、多くの言語で使えるはず。

// 平仮名4つ
System.out.println( "ひらがな".matches( "\\p{InHiragana}{4}" ) );
    // => true

// カタカナ4つ
System.out.println( "カタカナ".matches( "\\p{InKatakana}{4}" ) );
    // => true

// 漢字2つ
System.out.println( "漢字".matches( "\\p{InCjkUnifiedIdeographs}{2}" ) );
    // => true

指定文書でどのUnicodeブロックが使用されているか確認する

それぞれのブロックの意味についてはunicode.orgを見てもらうか、Wikipediaのこのページあたりを見てもらうかするとして、ここでは日本語で関わりがありそうなブロックのみを探してみることにします。

とりあえず文書を解析して、どのブロックが何度出現したかを調べる簡易コード。

// 解析対象文字
String str = "[Java]でUnicodeのブロックを、云々するソース。";

// NFKC(互換部品とそれに続く正規合成)をかけておく
str = Normalizer.normalize( str, Normalizer.Form.NFKC );

// どのブロックが何回使われたかカウントしてみる
Map<UnicodeBlock, Integer> result = new HashMap<UnicodeBlock, Integer>();
for( int i = 0; i < str.length(); i++ ) {
    UnicodeBlock block = UnicodeBlock.of( str.charAt( i ) );
    if( !result.containsKey( block ) ) {
        result.put( block, 0 );
    }
    result.put( block, result.get( block ) + 1 );
}

// 結果表示
for( Object key : result.keySet() ) {
    System.out.println( key + " : " + result.get( key ) );
}

// 結果
// => KATAKANA : 7
// => CJK_SYMBOLS_AND_PUNCTUATION : 3
// => CJK_UNIFIED_IDEOGRAPHS : 1
// => BASIC_LATIN : 13
// => HIRAGANA : 5

結果を見ての通り、「平仮名」は「HIRAGANA」、「カタカナ」は「KATAKANA」に分類され、「英字や記号」は「BASIC_LATIN」に分類されます。

漢字は「CJK_UNIFIED_IDEOGRAPHS」、句読点や「々」はCJK_SYMBOLS_AND_PUNCTUATIONに分類されているようです。

日本のサイトで実際に使用されているブロックを調べてみる

WEB上のjpドメインのページを2571個ほど適当に読み込んで(複数のポータルサイトからスタートして、本当に適当にリンクを辿ってもらいました)、各文書に登場するUnicodeBlockの数をカウントしてみました。

集計した文字数は全部で1億2千万くらい。タグを外して(というかDOMのTEXTの部分だけ読んで)、半角スペースを排除していますが、ScriptとかStyleタグの中身はカウントされいます。ので、英字・記号の発生率は普通の文書より高めになっていると思います。

けして多い母数とは言えないのと、エンコード失敗してる場合もあると思うので(レスポンスヘッダ見て指定してなければmeta見て判定はしてます)、まぁ、参考までの数値として。

UnicodeBlock日本語表記出現数出現率出現率合算
BASIC_LATIN基本ラテン文字6344756450.95821%50.95821%
CJK_UNIFIED_IDEOGRAPHSCJK統合漢字2130235017.10908%68.06729%
KATAKANA平仮名1890906715.18690%83.25419%
HIRAGANAカタカナ1808808214.52753%97.78172%
CJK_SYMBOLS_AND_PUNCTUATIONCJKの記号及び句読点23637191.89843%99.68015%
GEOMETRIC_SHAPES幾何学模様826690.06640%99.74655%
GENERAL_PUNCTUATION一般句読点607690.04881%99.79535%
SPECIALS特殊用途文字582950.04682%99.84217%
BOX_DRAWING罫線素片566230.04548%99.88765%
MISCELLANEOUS_SYMBOLSその他の記号538110.04322%99.93087%
ARROWS矢印285840.02296%99.95383%
LATIN_1_SUPPLEMENTラテン1補助208550.01675%99.97058%
MATHEMATICAL_OPERATORS数学記号 (演算子)150350.01208%99.98265%
GREEKギリシア文字及びコプト文字56280.00452%99.98717%
COMBINING_DIACRITICAL_MARKSダイアクリティカルマーク35260.00283%99.99000%
LATIN_EXTENDED_Bラテン文字拡張B31920.00256%99.99257%
LATIN_EXTENDED_Aラテン文字拡張A11810.00095%99.99352%
CYRILLICキリル文字10490.00084%99.99436%
IPA_EXTENSIONSIPA拡張 (国際音声記号)9690.00078%99.99514%
HEBREWヘブライ文字8460.00068%99.99582%
ARABICアラビア文字6240.00050%99.99632%
HIGH_SURROGATES上位代用符号位置5850.00047%99.99679%
THAANAターナ文字5720.00046%99.99725%
LOW_SURROGATES下位代用符号位置5330.00043%99.99767%
SYRIACシリア文字5280.00042%99.99810%
ARABIC_PRESENTATION_FORMS_Bアラビア表示形B3840.00031%99.99841%
null3540.00028%99.99869%
HANGUL_SYLLABLESハングル音節文字3170.00025%99.99895%
ARMENIANアルメニア文字2340.00019%99.99913%
SPACING_MODIFIER_LETTERS前進を伴う修飾文字2240.00018%99.99931%
CURRENCY_SYMBOLS通貨記号1930.00016%99.99947%
THAIタイ文字1520.00012%99.99959%
CYRILLIC_SUPPLEMENTARYキリール文字補助1370.00011%99.99970%
PRIVATE_USE_AREA外字領域1100.00009%99.99979%
CJK_UNIFIED_IDEOGRAPHS_EXTENSION_ACJK統合漢字拡張A900.00007%99.99986%
MISCELLANEOUS_TECHNICALその他の技術用記号750.00006%99.99992%
YI_SYLLABLESイ文字310.00002%99.99995%
MONGOLIANモンゴル文字250.00002%99.99997%
DINGBATS装飾記号160.00001%99.99998%
TAI_LEタイ・ロ文字100.00001%99.99999%
CHEROKEEチェロキー文字80.00001%99.99999%
DEVANAGARIデーヴァーナーガリー文字70.00001%100.00000%

見ての通り、BASIC_LATIN(基本ラテン文字)、CJK_UNIFIED_IDEOGRAPHS(漢字)、HIRAGANA(平仮名)、KATAKANA(カタカナ)4種類だけで全体の97.78%をカバー出来ています。

次に数の多いCJK_SYMBOLS_AND_PUNCTUATION(句読点とか)を加えると、99.68%。たいていの日本語の文はこの5種類で構成されていると思って良さそうです。

ちなみにこの結果は直前でNFKCで正規化しています。正規化しない場合は、HALFWIDTH_AND_FULLWIDTH_FORMS(全角記号とか半角カナなど)が1%程度発生していました。