背景
表記ゆれを改善するため、半角→全角にする必要があった。
以下のように実装したが、半角→全角にならず…。
/**
* 半角文字を全角文字に変換
* @param input 入力文字列
* @return 全角文字列
*/
public static String toZenkaku(Object input) {
String zenkaku = "";
if (input != null && !"".equals(input.toString().trim())) {
// 英数・カナ・記号などを全角に正規化
zenkaku = Normalizer.normalize(input.toString(), Normalizer.Form.NFKC);
// 全角スペースに変換
zenkaku = zenkaku.replace(" ", " ");
}
return zenkaku;
}
<Normalizer.Form.NFKCの挙動>
-
Normalizer.normalize(..., NFKC)
は「互換分解+正規化」 - 「NFKC」は、単に半角カナ→全角カナ変換をするものというわけではなく、Unicodeの「Composition」と「Compatibility」の変換をするものらしい
簡単に言うと「同じ意味の文字が複数あると検索でヒットしなかったりしてややこしいから1つに統一してしまおう」ということ。
修正後メソッド
<メソッド全体>
/**
* 半角文字を全角文字に変換
*
* @param input 入力文字列
* @return 全角文字列
*/
public static String toZenkaku(Object input) {
if (input == null || input.toString().trim().isEmpty()) {
return "";
} else {
String inStr = input.toString();
StringBuilder sb = new StringBuilder();
for (char c : inStr.toCharArray()) {
if (c >= 0x21 && c <= 0x7E) {
// 半角ASCIIを全角に変換
sb.append((char) (c - 0x21 + 0xFF01));
} else if (c == ' ') {
// 半角スペース → 全角スペース
sb.append(' ');
} else {
// そのまま
sb.append(c);
}
}
return sb.toString();
}
}
<シフト計算>
sb.append((char) (c - 0x21 + 0xFF01));
- 半角の
'!'
は0x21
- 全角の
'!'
は0xFF01
この差分が一定なので
「半角コード - 0x21 + 0xFF01」で全角コードに変換できる。
例:
-
半角
'1'
=0x31
→(0x31 - 0x21 + 0xFF01)
=0xFF11
= 全角'1'
-
半角
'A'
=0x41
→(0x41 - 0x21 + 0xFF01)
=0xFF21
= 全角'A'
-
半角
'~'
=0x7E
→(0x7E - 0x21 + 0xFF01)
=0xFF5E
= 全角'~'
※半角スペースだけ別扱いにしている理由
- 半角スペース
' '
=0x20
は指定した範囲0x21~0x7E
に含まれない。 - なので別途に変換する必要があります。
✅ まとめ
-
半角の記号・数字・英字(
0x21~0x7E
)を全角にずらす。 -
半角スペースを全角スペースに変換する。
という方法で実装しました。
しかし、調べてみた感じ、 ICU4Jという外部ライブラリの方が圧倒的に便利そうです。
↓ こんな感じで書けるらしい。
import com.ibm.icu.text.Transliterator;
public class Main {
public static void main(String[] args) {
String target = "全角文字"; // 変換対象の文字列
Transliterator fullToHalf = Transliterator.getInstance("Fullwidth-Halfwidth");
String result = fullToHalf.transliterate(target); // 全角から半角に変換
System.out.println(result); // 出力: 半角文字
}