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) もコード ポイントが複数になることがありますので、対応していません。
参考