全角→半角は「バラバラな入力を“同じもの”として扱う」ための技
業務システムで一番よくある地味トラブルの一つが、これです。
- 「1234」と「1234」が別物として扱われてしまう
- 「ABC」と「ABC」で検索結果が変わる
- ユーザーがフォームに全角スペースを入れて、意図しない空白になる
人間の目には「同じ」に見えるのに、プログラム的には違う文字。
これを揃えるための基本テクニックが 全角→半角変換 です。
ここをユーティリティとしてきちんと用意しておくと、検索・比較・キー生成・ログ出力などが一気に安定します。
まずは「何を全角→半角にしたいか」を決める
全角と半角の代表例をざっくり整理する
よく対象になるのは、だいたいこのあたりです。
- 数字:
0123…9→0123…9 - 英字:
ABC…Zabc…z→A…Z a…z - 記号:
!#$%&()=~…→!#$%&()=~... - スペース:全角スペース → 半角スペース
カタカナ(全角↔半角)は別テーマとして扱うことが多いので、
ここでは「数字・英字・記号・スペース」を中心にします。
重要なのは、「どこまでを変換対象にするかをプロジェクトとして決める」ことです。
「数字と英字だけ」「スペースも含める」「記号はそのまま」など、用途によって変わります。
シンプルな実装:自前マッピングで全角→半角
「全角のコード範囲」を知ってしまえば、変換は実は単純
全角の英数字は、Unicode 上で連続した範囲に並んでいます。
例えば、全角の 0〜9 は、半角の 0〜9 に一定のオフセットを足した位置にあります。
これを利用すると、こんな感じのユーティリティが書けます。
public final class ZenkakuConverter {
private ZenkakuConverter() {}
public static String toHankakuAscii(String text) {
if (text == null || text.isEmpty()) {
return text;
}
StringBuilder sb = new StringBuilder(text.length());
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
// 全角英数字・記号(!〜~)の範囲
if (ch >= '!' && ch <= '~') {
// Unicode 上で 0xFEE0 だけずらすと半角になる
ch = (char) (ch - 0xFEE0);
} else if (ch == ' ') {
// 全角スペースは個別対応
ch = ' ';
}
sb.append(ch);
}
return sb.toString();
}
}
Java使い方はこうです。
String s = "Hello! 1234ABCabc";
String converted = ZenkakuConverter.toHankakuAscii(s);
System.out.println(converted);
// Hello! 1234ABCabc
Javaここで深掘りしたい重要ポイントは二つです。
一つ目は、「全角英数字・記号は、Unicode 上で“0xFEE0 ずらす”だけで半角になる」という性質を使っていることです。'!'〜'~' の範囲に入っている文字だけを対象にして、- 0xFEE0 してあげると、対応する半角に変わります。
二つ目は、「全角スペースだけは範囲外なので、個別に ' ' → ' ' と変換している」ことです。
全角スペースは見落とされがちですが、検索やトリム処理でかなりの地雷になるので、
全角→半角ユーティリティでは真っ先に対応しておくべき存在です。
例題:検索用に「英数字だけ半角に揃える」
入力値を正規化してから検索する
例えば、ユーザーが「商品コード」を検索する画面を考えます。
- DB には
ABC123で保存されている - ユーザーは「ABC123」「ABC123」「ABC123」など、好きなように入力してくる
このとき、「検索前に英数字を半角に揃える」だけで、ヒット率が一気に上がります。
public final class SearchNormalizer {
private SearchNormalizer() {}
public static String normalizeCodeInput(String input) {
if (input == null) {
return null;
}
// 英数字・記号・スペースを半角に
String hankaku = ZenkakuConverter.toHankakuAscii(input);
// 前後の空白を削る
return hankaku.trim();
}
}
Java使い方はこうです。
String raw = " ABC123 ";
String normalized = SearchNormalizer.normalizeCodeInput(raw);
System.out.println("\"" + normalized + "\""); // "ABC123"
Javaここでのポイントは、「“検索用の正規化”という文脈をユーティリティ名に刻んでいる」ことです。normalizeCodeInput と名前をつけることで、「これは検索用コード入力のための正規化なんだな」と一目で分かります。
全角→半角はあくまで“正規化の一部”なので、
- トリム(前後の空白削除)
- 大文字・小文字の統一
- 不要な記号の除去
などと組み合わせて、「このシステムではコードをこう扱う」というルールを一箇所に閉じ込めておくのが実務的です。
Java 標準の Normalizer を使うという選択肢
Unicode 正規化(NFKC)で「似た文字」をまとめる
もう少し広く「似た文字を同一視したい」ときに使えるのが、java.text.Normalizer です。
import java.text.Normalizer;
public final class UnicodeNormalizer {
private UnicodeNormalizer() {}
public static String toNfkc(String text) {
if (text == null) {
return null;
}
return Normalizer.normalize(text, Normalizer.Form.NFKC);
}
}
Javaこれを使うと、全角英数字だけでなく、いろいろな「互換文字」が標準的な形に寄せられます。
String s = "Hello! ① Ⅰ ㍻";
System.out.println(UnicodeNormalizer.toNfkc(s));
// Hello! 1 I 平成
Javaここで深掘りしたいのは、「Normalizer.NFKC は“全角→半角”だけではなく、“互換文字を標準形に寄せる”かなり強力な変換」だということです。
- 全角英数字 → 半角
- 丸付き数字 → 通常の数字
- ローマ数字 → 通常のアルファベット
- 一部の合成文字 → 分解された形
など、かなり広範囲に影響します。
だからこそ、
- 「英数字だけ半角にしたい」なら自前マッピング(さっきの
ZenkakuConverter) - 「とにかく“見た目が同じもの”を同一視したい」なら NFKC
というように、用途に応じて使い分けるのが大事です。
例題:ログ出力時に「英数字だけ半角にしておく」
ログを後から grep しやすくするための一手間
ログにユーザー入力をそのまま出すと、全角英数字が混ざっていて grep しづらい、ということがよくあります。
そこで、「ログに出す前に英数字だけ半角に揃える」というユーティリティを挟んでおくと便利です。
public final class LogSafeStrings {
private LogSafeStrings() {}
public static String normalizeForLog(String text) {
if (text == null) {
return null;
}
// 英数字・記号・スペースを半角に
String hankaku = ZenkakuConverter.toHankakuAscii(text);
// 制御文字などを消す処理を足してもよい
return hankaku;
}
}
Java使い方はこうです。
String userInput = "ユーザー名: TestUser1";
System.out.println("input=" + LogSafeStrings.normalizeForLog(userInput));
// input=ユーザー名: TestUser1
Javaここでのポイントは、「ログ用の正規化ルールを一箇所にまとめている」ことです。
あとから「タブをスペースにしたい」「制御文字を消したい」といった要件が出ても、LogSafeStrings だけ直せば、ログ出力全体の挙動を変えられます。
まとめ:全角→半角ユーティリティで身につけたい感覚
全角→半角は、「人間には同じに見えるけれど、プログラム的には違う文字」を揃えるための、超・基礎テクニックです。
押さえておきたい感覚は、まず「全角英数字・記号は '!'〜'~' の範囲を 0xFEE0 ずらすだけで半角になる」という事実。
次に、「全角スペースは個別に ' ' → ' ' と変換しないと、検索やトリムで地雷になる」ということ。
そして、「検索用・ログ用など、文脈ごとに“どこまで正規化するか”を決め、そのルールをユーティリティクラスに閉じ込めてプロジェクト全体で共有する」ことです。
もしあなたのコードのどこかに、replace(' ', ' ') や「全角と半角が混ざった比較」が散らばっているなら、
それを題材にして、ここで作った ZenkakuConverter や SearchNormalizer、LogSafeStrings に置き換えてみてください。
それだけで、「検索しやすくて、比較しやすくて、ログも読みやすい文字列処理」に、一段レベルアップできます。
