6
1

More than 1 year has passed since last update.

Java で Unicode の Fullwidth や Halfwidth を判定する方法

Last updated at Posted at 2022-09-29

ICU4J ライブラリーを使って Unicode の East Asian Width プロパティーを取得することで、Unicode としての全角・半角を判定することができます。

import com.ibm.icu.lang.CharacterProperties;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.lang.UProperty;
import com.ibm.icu.util.CodePointMap;

public class EastAsianWidthChecker {
    private static final CodePointMap eastAsianWidthMap =
            CharacterProperties.getIntPropertyMap(UProperty.EAST_ASIAN_WIDTH);

    /**
     * @return {@link UCharacter.EastAsianWidth#NARROW NARROW},
     *         {@link UCharacter.EastAsianWidth#HALFWIDTH HALFWIDTH},
     *         {@link UCharacter.EastAsianWidth#AMBIGUOUS AMBIGUOUS},
     *         {@link UCharacter.EastAsianWidth#FULLWIDTH FULLWIDTH},
     *         {@link UCharacter.EastAsianWidth#WIDE WIDE},
     *         {@link UCharacter.EastAsianWidth#NEUTRAL NEUTRAL} のいずれか。
     */
    public static int eastAsianWidthOf(int codePoint) {
        return eastAsianWidthMap.get(codePoint);
    }
}

戻り値の NARROW と HALFWIDTH は半角、WIDE と FULLWIDTH は全角、NEUTRAL はどちらでもない文字を表します。

AMBIGUOUS はギリシャ文字のように東アジアで2バイト文字だけれどもヨーロッパでは1バイト文字であるものに使われます。Unicode としては曖昧な幅ですが、我々にとっては全角であることが多いでしょう。以下では全角として扱っていますが、場合によりけりだと思います。

動かしてみた

次のようなクラスを作って実行してみました。switch 式を使ってしまったので Java 14 以降が必要です。

import static com.ibm.icu.lang.UCharacter.EastAsianWidth.*;

public class Test {
    public static void main(String[] args) {
        "aaβ○カがが茶茶丳𠮷㍍㌀😄क".codePoints().forEach(codePoint -> {
            int unicodeWidth = EastAsianWidthChecker.eastAsianWidthOf(codePoint);
            String result = switch (unicodeWidth) {
                case NARROW -> "半角 (Narrow)";
                case HALFWIDTH -> "半角 (Halfwidth)";
                case AMBIGUOUS -> "全角 (Ambiguous)";
                case FULLWIDTH -> "全角 (Fullwidth)";
                case WIDE -> "全角 (Wide)";
                case NEUTRAL -> "どちらでもない (Neutral)";
                default -> "どちらでもない (" + unicodeWidth + ")";
            };

            System.out.printf(
                    "「%s」(U+%04X) は Unicode で%s。%n",
                    Character.toString(codePoint), codePoint, result
            );
        });
    }
}

実行結果は次のようになりました。

「a」(U+0061) は Unicode で半角 (Narrow)。
「a」(U+FF41) は Unicode で全角 (Fullwidth)。
「β」(U+03B2) は Unicode で全角 (Ambiguous)。
「○」(U+25CB) は Unicode で全角 (Ambiguous)。
「カ」(U+FF76) は Unicode で半角 (Halfwidth)。
「が」(U+304C) は Unicode で全角 (Wide)。
「か」(U+304B) は Unicode で全角 (Wide)。
「゙」(U+3099) は Unicode で全角 (Wide)。
「茶」(U+8336) は Unicode で全角 (Wide)。
「茶」(U+F9FE) は Unicode で全角 (Wide)。
「丳」(U+4E33) は Unicode で全角 (Wide)。
「𠮷」(U+20BB7) は Unicode で全角 (Wide)。
「㍍」(U+334D) は Unicode で全角 (Wide)。
「㌀」(U+3300) は Unicode で全角 (Wide)。
「😄」(U+1F604) は Unicode で全角 (Wide)。
「क」(U+0915) は Unicode でどちらでもない (Neutral)。
「」(U+E000) は Unicode で全角 (Ambiguous)。

U+E000 は私用領域なので、本当に全角かは場合によると思います。Qiita では文字化けしていますが、手元の環境では全角の虫眼鏡が表示されます。

注意点

結合文字には対応していません。例えば「か」と「濁点」を表す "\u304b\u3099" は意味的には「が」を表しますが、2つのコード ポイントですので、上記の方法では1文字とは認識できません。同様に、書記素クラスター (grapheme cluster) もコード ポイントが複数になることがありますので、対応していません。

参考

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1