Mar 19, 2006

Normalizer にチャレンジ

Normalizer とは

java.text.Normalize は Mustang から導入された文字列処理用のクラス。 Unicode 文字列の正規化を行ってくれる。 今まで独自のコードでやっていた処理を Normalizer に置き換えられそうなのでチェックしてみた。

Class Normalizer
http://download.java.net/jdk6/doc/api/java/text/Normalizer.html
Enum Normalizer.Form
http://download.java.net/jdk6/doc/api/java/text/Normalizer.Form.html
Normalization Charts
http://www.unicode.org/charts/normalization/

Normalizer では、以下の 4 つの Normalization Form が定義されている。

  • NFC - Canonical decomposition, followed by canonical composition.
  • NFD - Canonical decomposition.
  • NFKC - Compatibility decomposition, followed by canonical composition.
  • NFKD - Compatibility decomposition.
同じ文字でもそれぞれの Form で文字コード上の表現が変化する。

変換結果

日本語を使用するアプリケーションで頻繁に変換処理が行われる文字をチェックしてみた。 NFKC 変換が現在の独自ロジックでの変換の置き換えに使用できそう。 但し、色々試してみたところ多少不足があるので単純な置き換えは無理。

ORIGINAL ->      NFC        NFD          NFKC          NFKD
-------------------------------------------------------------
¢ (00A2) ->   ¢ (00A2)  ¢ (00A2)  ¢ (00A2)  ¢ (00A2)
¢ (FFE0) ->   ¢ (FFE0)  ¢ (FFE0)  ¢ (00A2)  ¢ (00A2)
£ (00A3) ->   £ (00A3)  £ (00A3)  £ (00A3)  £ (00A3)
£ (FFE1) ->   £ (FFE1)  £ (FFE1)  £ (00A3)  £ (00A3)
¬ (00AC) ->   ¬ (00AC)  ¬ (00AC)  ¬ (00AC)  ¬ (00AC)
¬ (FFE2) ->   ¬ (FFE2)  ¬ (FFE2)  ¬ (00AC)  ¬ (00AC)
- (002D) ->   - (002D)  - (002D)  - (002D)  - (002D)
- (FF0D) ->   - (FF0D)  - (FF0D)  - (002D)  - (002D)
| (007C) ->   | (007C)  | (007C)  | (007C)  | (007C)
| (FF5C) ->   | (FF5C)  | (FF5C)  | (007C)  | (007C)
~ (007E) ->   ~ (007E)  ~ (007E)  ~ (007E)  ~ (007E)
~ (FF5E) ->   ~ (FF5E)  ~ (FF5E)  ~ (007E)  ~ (007E)
が (304C) ->   が (304C)  か? (304B3099)  が (304C)  か? (304B3099)
ぎ (304E) ->   ぎ (304E)  き? (304D3099)  ぎ (304E)  き? (304D3099)
ぱ (3071) ->   ぱ (3071)  は? (306F309A)  ぱ (3071)  は? (306F309A)
ぴ (3074) ->   ぴ (3074)  ひ? (3072309A)  ぴ (3074)  ひ? (3072309A)
㍉ (3349) ->   ㍉ (3349)  ㍉ (3349)  ミリ (30DF30EA)  ミリ (30DF30EA)
㌔ (3314) ->   ㌔ (3314)  ㌔ (3314)  キロ (30AD30ED)  キロ (30AD30ED)
㎜ (339C) ->   ㎜ (339C)  ㎜ (339C)  mm (006D006D)  mm (006D006D)
㎡ (33A1) ->   ㎡ (33A1)  ㎡ (33A1)  m2 (006D0032)  m2 (006D0032)
㍻ (337B) ->   ㍻ (337B)  ㍻ (337B)  平成 (5E736210)  平成 (5E736210)
㍼ (337C) ->   ㍼ (337C)  ㍼ (337C)  昭和 (662D548C)  昭和 (662D548C)
№ (2116) ->   № (2116)  № (2116)  No (004E006F)  No (004E006F)
㏍ (33CD) ->   ㏍ (33CD)  ㏍ (33CD)  KK (004B004B)  KK (004B004B)
℡ (2121) ->   ℡ (2121)  ℡ (2121)  TEL (00540045004C)  TEL (00540045004C)
㊤ (32A4) ->   ㊤ (32A4)  ㊤ (32A4)  上 (4E0A)  上 (4E0A)
㊥ (32A5) ->   ㊥ (32A5)  ㊥ (32A5)  中 (4E2D)  中 (4E2D)
㈱ (3231) ->   ㈱ (3231)  ㈱ (3231)  (株) (0028682A0029)  (株) (0028682A0029)
㈲ (3232) ->   ㈲ (3232)  ㈲ (3232)  (有) (002867090029)  (有) (002867090029)

サンプルコード

package jp.in_vitro.codelets.text;

import java.text.Normalizer;

public class Codelet {

    public Codelet() {
        super();
    }

    public static void main(String[] args) {
        Codelet me = new Codelet();
        me.execute();
    }

    protected void execute() {

        String targets = "\u00A2\uFFE0\u00A3\uFFE1\u00AC\uFFE2\u002D\uFF0D\u007C\uFF5C\u007E\uFF5Eがぎぱぴ㍉㌔㎜㎡㍻㍼№㏍℡㊤㊥㈱㈲";
        System.out
                .println("ORIGINAL ->      NFC        NFD          NFKC          NFKD");
        System.out
                .println("-------------------------------------------------------------");
        for (char ch : targets.toCharArray()) {
            this.normalize("" + ch);
        }
    }

    protected void normalize(final String target) {
        String normalized = null;
        String normalizedHex = null;

        System.out.print("" + target + " (" + this.toHex(target) + ") -> ");

        normalized = Normalizer.normalize(target, Normalizer.Form.NFC);
        normalizedHex = this.toHex(normalized);
        System.out.print("  " + normalized + " (" + normalizedHex + ")");

        normalized = Normalizer.normalize(target, Normalizer.Form.NFD);
        normalizedHex = this.toHex(normalized);
        System.out.print("  " + normalized + " (" + normalizedHex + ")");

        normalized = Normalizer.normalize(target, Normalizer.Form.NFKC);
        normalizedHex = this.toHex(normalized);
        System.out.print("  " + normalized + " (" + normalizedHex + ")");

        normalized = Normalizer.normalize(target, Normalizer.Form.NFKD);
        normalizedHex = this.toHex(normalized);
        System.out.print("  " + normalized + " (" + normalizedHex + ")");

        System.out.println();
    }

    protected String toHex(final String str) {

        StringBuffer buf = new StringBuffer();
        for (char ch : str.toCharArray()) {
            buf.append(Integer.toString((int) ((ch >> 12) & 0x0F), 16)
                    .toUpperCase());
            buf.append(Integer.toString((int) ((ch >> 8) & 0x0F), 16)
                    .toUpperCase());
            buf.append(Integer.toString((int) ((ch >> 4) & 0x0F), 16)
                    .toUpperCase());
            buf.append(Integer.toString((int) (ch & 0x0F), 16).toUpperCase());
        }
        return new String(buf);
    }
}

TrackBack ping me at
http://www.in-vitro.jp/blog/index.cgi/Mustang/20060319_01.trackback
Post a comment

writeback message: Ready to post a comment.