テクノロジー
全角・空白・Unicodeの正規化は入口で1回だけ
「検索しても出てこない」「同じメールアドレスで二重登録できた」。こうした報告の原因は、ロジックではなく入力値の揺れであることが少なくありません。全角数字、前後の空白、見た目が同じ別の文字。これらを実装の入口でどう揃えるかは、実装フェーズで決めておく設計判断です。
見た目は同じなのに別の値になる例
- 「09012345678」と「09012345678」: 全角と半角で一致しない
- 「taro@example.com 」: 末尾の空白つきでユーザー検索に引っかからない
- 「Taro@Example.com」と「taro@example.com」: 大文字小文字違いで二重登録できる
- 「が」を1文字で表した場合と「か」+濁点で表した場合: 見た目は同じでも比較すると不一致になる
正規化の対象一覧
- 全角・半角: 数字、英字、記号、半角カナ
- 空白: 前後の空白、全角スペース、ゼロ幅スペース
- 改行コード: CRLF と LF の混在
- Unicode 正規化: 結合文字(濁点の分離など)
- 大文字小文字: メールアドレスやユーザー名など、区別しない項目のみ
正規化は入口の1か所に絞る
各画面や各処理で個別に整えると、1か所の漏れが重複登録や検索漏れになります。API の受け口(コントローラやフォームの送信処理)で1回だけ行い、以降は正規化済みの値だけを扱います。
export function normalizeText(input: string): string {
return input
.normalize("NFKC") // 全角半角・結合文字を統一
.replace(/\r\n?/g, "\n") // 改行を LF に
.replace(/[-]/g, "") // ゼロ幅文字を除去
.trim(); // 前後の空白を除去
}
export function normalizeEmail(input: string): string {
return normalizeText(input).toLowerCase();
}NFKC は全角空白(U+3000)も半角空白に変えるため、trim の前に通すのがポイントです。
保存値と表示値を分けるべきケース
NFKC は「①」を「1」に、「㈱」を「(株)」に変えます。氏名や商品名など、入力された形そのものに意味がある項目は、元の値を表示用に残し、検索や重複判定にだけ正規化した値を使います。
- メールアドレス、電話番号、郵便番号: 正規化した値だけ保存してよい
- 氏名、住所、商品名: 表示用は原文のまま、検索用の列を別に持つ
実装後の確認チェックリスト
- 全角数字や半角カナを入れて保存し、半角で検索して見つかるか
- 末尾に全角スペースを付けて送信し、前後が除去されるか
- 大文字と小文字だけが違うメールアドレスで二重登録が弾かれるか
- 正規化の関数が入口の1か所にしかないか(検索で grep して確認)
- DB の一意制約は正規化済みの値にかかっているか
Bugoon での実践
入力値の揺れによるバグは、報告者が「何を入力したか」を書き忘れると再現できません。Bugoon のウィジェットをサイトに埋め込むと、スクリーンショットへのアノテーションと操作ステップの記録が報告に付くため、入力した値と画面の状態を開発者が確認できます。GitHub Issue 連携で起票し、MCP サーバー経由で Claude Code や Cursor に修正を任せる流れにもつなげられます。
← 記事一覧に戻るBugoon Blog