お問い合わせ
お問い合わせ 03-5835-2820(平日 9:00〜18:00)

JAPANESE FORM VALIDATION FIELD GUIDE

日本語フォーム
バリデーション大全

𠮷野家さんが「4文字」と数えられる。髙橋さんが「使えない文字」と言われる。ジョン・スミスさんはそもそも入力できない。
日本語の入力フォームに潜む落とし穴を、その場で壊れる様子を試せる体験デモつきで集めた実装リファレンスです。

最終更新:2026-07-06 デモはすべてブラウザ内で完結します(入力内容はどこにも送信されません)

このページの考え方

ここに載っているのは「珍しいバグ」ではありません。実在する名前・住所・メールアドレスが、ありふれた実装で壊れるという話です。 入力チェックの目的はユーザーを弾くことではなく、正しいデータを受け取ることです。だから本ページの結論はほぼ一貫しています―― 機械が直せるものは機械が直す。人間の実在を「不正な入力」と呼ばない。

各エントリのデモは分かりやすさ優先の簡易再現です(実在の特定サービスの再現ではありません)。「正しい実装」も前提により最適解は変わります。コピペの際は要件に合わせて調整してください。

A氏名・人名

名前は本人確認の起点であり、最も「実在」と衝突しやすい入力欄。ここが壊れているフォームは、実在の顧客を入口で断っています。

A-01

「𠮷野家」が4文字と数えられる ―― サロゲートペア

症状:文字数カウント・文字数制限・切り詰めで、実在の名前が壊れたり弾かれたりする。

体験デモ:文字数を数えてみる

str.length(よくある実装)-
コードポイント数 [...str].length-
書記素数(見た目の文字数)-
「1文字目」を str[0] で取り出すと-

なぜ起きるか

JavaScriptの .length が返すのは「文字数」ではなくUTF-16コード単位の数です。「𠮷」(U+20BB7)は基本多言語面の外にある文字で、UTF-16では2単位(サロゲートペア)を使います。だから「𠮷野家」は .length === 4。 同様に str[0]substring での切り詰めはサロゲートペアを真っ二つにし、壊れた文字(�)を作ります。DBの列定義がバイト数や UTF-16 単位数ベースの場合、保存時の切り詰めでも同じことが起きます。

正しい実装

// 「文字数」を数えるなら書記素(見た目の1文字)で数える
const seg = new Intl.Segmenter('ja', { granularity: 'grapheme' });
const count = [...seg.segment(value)].length; // 「𠮷野家」→ 3

// str.length は UTF-16 コード単位の数(「𠮷野家」→ 4)
// [...value].length はコードポイントの数(𠮷 は1になるが、結合文字は分かれる)

切り詰めが必要な場合も書記素単位で行う。DB側はUTF-8(MySQLなら utf8mb4)で、アプリと同じ単位の長さ定義にそろえる。

現実の被害

「𠮷」を「吉」で登録させる運用は、本人確認書類との不一致を生みます。金融・行政・契約系では「表記が違う」こと自体が手続きの差し戻し理由になり、ユーザーには直せません。

A-02

髙橋さんと山﨑さんが「使えない文字」と言われる ―― 旧字体・異体字

症状:戸籍上の正式な字(﨑・髙・濵・彅 など)が「不正な文字が含まれています」で弾かれる。

体験デモ:昔ながらの文字チェックに名前を通す(JIS X 0208範囲チェックの簡易再現)

※代表的な表外字を検出する簡易再現です(完全なJIS X 0208判定ではありません)。

なぜ起きるか

「使える文字=Shift_JIS(JIS X 0208)の範囲」という20世紀の制約が、チェックロジックだけ現代に生き残っているためです。 「﨑」「髙」「濵」はJIS X 0208に無い拡張文字(いわゆるIBM拡張系)、「彅」はJIS X 0213で追加された字。どれもWindowsの標準的な日本語環境(CP932)で普通に入力でき、戸籍上はそれが正式な字です。 システムがUTF-8で動いているのに、バリデーションだけが旧時代の文字集合を守っているケースが非常に多い。

正しい実装

// 「使える文字の一覧」で弾かない。制限は要件から最小限に積み上げる
// 例:制御文字だけを拒否する(旧字体・異体字はすべて通る)
if (/\p{C}/u.test(value)) {
  // 制御文字・不可視文字が混入している場合のみエラー
}

// 下流システムの制約でどうしても受けられない字がある場合は、
// 黙って「不正な文字」と言わず、理由と代替手段を明示する

原則は「文字集合の白リストで名前を弾かない」。下流の基幹システム等にどうしても受けられない字がある場合は、エラーではなく理由の説明と代替手段の案内に切り替える。

現実の被害

髙橋・山﨑・濵田は日本の多数派クラスの姓です。「あなたの名前は不正です」という体験は単なる離脱では済まず、その後の指名検索や紹介にも響く不信を残します。

A-03

仕様書の「JIS第1・第2水準のみ」という時代錯誤

症状:要件定義の段階で「使える文字」が狭く固定され、実在の名前が仕様として弾かれる。

体験デモ:文字の「区分」を見てみる(1字ずつ判定)

※「基本」=ひらがな・カタカナ・基本漢字ブロック、「拡張」=互換漢字・拡張ブロック等、「BMP外」=サロゲートペアが必要な字、の簡易区分です。

なぜ起きるか

「氏名はJIS第1・第2水準の範囲とする」という一文が、仕様書のテンプレとしてコピーされ続けているためです。 一方で戸籍・住民記録の世界が扱う文字は桁違いに広く、行政のシステム標準化では文字情報基盤(MJ)ベースで約6万字規模の文字が前提になっています(デジタル庁の文字要件・文字環境導入実践ガイドブック参照)。 「第1・第2水準」は約6千字。実在の名前の世界より一桁狭い檻です。

正しい実装

新規開発ならUTF-8で受けてUTF-8で保存するが出発点。制限が必要な場合も「JIS第◯水準」ではなく、要件から積み上げる(制御文字を除く、絵文字を除く、など)。 仕様書に文字集合の制限を書くときは「なぜその範囲か」の根拠を必ず添える――書けないなら、その制限は多分不要です。

現実の被害

仕様として弾いている場合、現場では直せません。改修は「文字コード全面見直し」になりがちで、最初にUTF-8で作っていれば0円だったコストが数百万円規模の負債になります。

A-04

姓と名に分けられない人がいる ―― 姓名分割の強制

症状:「姓」「名」が両方必須のフォームに、単名の人・ミドルネームのある人が入力できない。

体験デモ:姓・名 両方必須のフォーム

なぜ起きるか

「人の名前は姓と名の2つでできている」という前提が、そもそも普遍ではないためです。姓を持たない・単名の名前、複合姓、ミドルネーム、名乗りの順序が違う名前は世界中にあり、日本国内にも帰化・国際結婚などで普通に存在します。 海外では "Falsehoods Programmers Believe About Names"(プログラマが名前について信じている誤謬)という古典ドキュメントがあるほど、繰り返されてきた設計ミスです。

正しい実装

<!-- 可能ならフルネーム1欄で受ける -->
<label for="name">お名前</label>
<input id="name" name="name" autocomplete="name" />

<!-- 業務上どうしても分割が必要な場合も「名」を必須にしない
     (単名・複合姓・ミドルネームは2分割できない) -->

現実の被害

登録フォームを通れない=顧客になれない、が文字通りに起きます。回避のために「名」へ記号やダミー文字を入れさせる運用は、下流の帳票・本人確認をさらに壊します。

A-05

「氏名は2文字以上10文字以内」という根拠なき檻

症状:1文字の姓・長い名前が「短すぎます」「長すぎます」で弾かれる。

体験デモ:「2〜10文字」チェックのフォーム

なぜ起きるか

「だいたいこのくらいだろう」という感覚値が、そのままバリデーションになっているためです。1文字の姓(王・林・南 など)も、カタカナで30文字を超えるフルネームも実在します。 上限はDB列幅の都合であることが多いですが、それはDBの設計をユーザーに請求しているだけです。

正しい実装

// 下限は1、上限は「業務の必然」がある場合のみ、十分に大きく
const seg = new Intl.Segmenter('ja', { granularity: 'grapheme' });
const len = [...seg.segment(value)].length;
if (len < 1 || len > 100) {
  // 100書記素を超える氏名を弾く。2〜10文字のような檻を作らない
}

現実の被害

中国や韓国の姓はそのほとんどが漢字1文字で、日本で暮らすその姓の人たちも当然1文字のまま生活しています。「氏名は2文字以上」は、その全員を入口で断る仕様だと自覚して書いているか、が問われます。

A-06

ジョン・スミスさんが3回エラーになる ―― 外国人名を想定しない検証

症状:中黒(・)、スペース、アルファベットが「使用できない文字」になり、外国人の名前が入力できない。

体験デモ:「カタカナのみ・記号/スペース不可」のフリガナ欄

なぜ起きるか

フリガナ欄の正規表現が「全角カタカナの連続」だけを想定しているためです。区切りの中黒(・)、姓名間のスペース、長音(ー)、そしてそもそもカタカナ表記を持たない名前――どれも珍しい入力ではありません。 「カタカナのみ」と「実在の名前」を両立させるには、最低限の記号を許可リストに足すだけで済みます。

正しい実装

// フリガナをカタカナに限定する場合も、実在の名前に必要な字を許可する
// 中黒(・)・長音(ー)・スペース(全角/半角)
const re = /^[\u30A1-\u30FA\u30FC\u30FB\u3000 ]+$/;

// そもそも「フリガナ必須」自体を見直す選択肢もある
// (autocomplete属性で自動入力される名前にはフリガナが無い)

現実の被害

外国籍の顧客・従業員は入口で詰みます。ECなら購入できない、採用フォームなら応募できない。国際化対応の第一歩は多言語化ではなく、名前が入ることです。

Bメールアドレス

メール欄の結論は一つに集約されます――形式チェックで頑張るほど損をする。規格に完全準拠すると実在のアドレスを弾き、本当の検証は「届くかどうか」でしか行えないからです。

B-01

RFC違反のメールアドレスは実在する ―― ドコモ旧仕様

症状:連続ドット(abc..def@)や@直前ドット(abc.@)のアドレスが「形式が正しくありません」で登録できない。だが、そのアドレスは長年実際に使われている。

体験デモ:同じアドレスを2種類のチェックに通す

RFC準拠の厳格チェック-
現実的なチェック(@の有無+確認メール前提)-

なぜ起きるか

かつてのドコモ(2009年頃まで)では、RFCが許さない形式――ドットの連続や@直前のドット――を含むアドレスが取得できました。迷惑メール回避のためにあえて複雑なアドレスにした利用者も多く、今もそのまま使われています。ドコモ自身が「RFCに違反するメールアドレスをご利用のお客様へ」という案内ページを公開しているほど、公式に認知された歴史です。 iOS 14のメールアプリがこの種のアドレスへ送信できなくなり、話題になったこともあります(2020年)。

正しい実装

// メールの形式チェックは最小限に。実在確認は「確認メールが届くか」で行う
const looksLikeEmail = (v) => {
  const at = v.indexOf('@');
  return at > 0 && at === v.lastIndexOf('@') && at < v.length - 1 && !/\s/.test(v);
};
// 形式チェックはこの程度で十分。
// 本当の検証=確認メールのリンクをクリックしてもらう(ダブルオプトイン)

「規格上正しいか」ではなく「その顧客に届くか」が業務要件のはず。厳格な形式チェックは、ガラケー時代からアドレスを使い続けている長期顧客を弾きます。

現実の被害

この問題が顕在化するのは会員サイトのリニューアルやEC移行のとき。「今まで使えていたメールアドレスが新システムで登録できない」は、最も説明しづらいクレームの一つです。

B-02

「完璧なメール正規表現」は存在しない

症状:どこかからコピーしてきた正規表現が、実在のアドレスを弾いたり、チェック同士で判定が食い違ったりする。

体験デモ:同じアドレスを3つの「よく見る」チェックに通すと判定が割れる

ネットでよく見る簡易正規表現-
HTML5 type="email" 相当-
RFC寄りの厳格チェック-

なぜ起きるか

メールアドレスの正式な文法(RFC 5321/5322)は引用文字列やコメントまで許す複雑なもので、正規表現での完全な再現は現実的に不可能です。しかも仮に完全再現できても、B-01のような「規格違反だが実在する」アドレスを弾いてしまう。 つまり形式チェックは、厳しくするほど実在の顧客を失い、緩くしても実在確認にはならない――投資対効果が構造的に低いのです。

正しい実装

「@が1つあり、前後に文字があり、空白を含まない」程度で通し、確認メール(ダブルオプトイン)を本検証にする。ブラウザ標準の type="email" を使うなら、それ以上に厳しい独自正規表現を重ねない。

現実の被害

タイポ(gmial.com等)は正規表現では検出できず、厳格チェックは実在アドレスを弾く。「形式は完璧なのに届かないアドレス」は素通しになる。形式チェックへの過剰投資は、防げないものを防ごうとして、防ぐ必要のないものを弾く行為です。

B-03

Gmailの「+」を弾くな ―― プラスエイリアス

症状:taro+shop@gmail.com のような「+」入りアドレスが「使用できない記号」として弾かれる。

体験デモ:「英数字とドットのみ」チェックのメール欄

なぜ起きるか

「+」はRFC上まったく正当な文字で、GmailやOutlook.comが公式にサポートするエイリアス機能(taro+タグ@)に使われます。弾いている理由はただ一つ、正規表現を書いた人が「+」を知らなかったから。

正しい実装

許可する。それだけです。B-02の方針(形式チェックは最小限)に従っていれば、そもそもこの問題は発生しません。

現実の被害

+エイリアスを使うのは、メールを整理・追跡しているITリテラシーの高い層――つまりB2Bなら情報システム担当者や技術者、まさに「弾いてはいけない見込み客」です。しかも「+を弾くフォーム」はその層のSNSで定期的に晒されます。

B-04

全角で入力されたメールアドレスは「エラー」ではなく「直せる入力」

症状:taro@example.com のような全角入力が「正しい形式で入力してください」で突き返される。

体験デモ:弾くフォーム vs 直すフォーム

弾くフォームの応答-
直すフォーム(NFKC正規化)の結果-

なぜ起きるか

スマホで日本語入力のままメールアドレスを打つと全角になります。画面上の「taro」と「taro」の違いは、多くの利用者には見分けがつきません。 そして機械にとっては、この変換は1行で解決する問題です(Unicode正規化 NFKC)。1行を惜しんで、入力者に「全角と半角の区別」という知識を要求しているのが現状のフォームです。

正しい実装

// 弾く前に正規化する。全角英数字・@・.はNFKCで半角に戻る
const normalized = value.normalize('NFKC');
// 「taro@example.com」→「taro@example.com」
// 正規化結果は入力欄に反映してユーザーにも見せてから、検証・送信する

現実の被害

「正しく入力したのにエラーになる」体験は、原因が見えないぶん最も離脱率が高いタイプのエラーです。サポート窓口への「登録できない」問い合わせの定番でもあり、1行の正規化で消せるコストです。

C電話番号

日本の電話番号は固定10桁・携帯11桁・0120は10桁と、そもそも長さが一定ではありません。「電話番号とはこういうもの」という思い込みが、そのままエラーメッセージになりがちな欄です。

C-01

「電話番号=携帯の11桁」という決めつけ

症状:固定電話・050のIP電話・0120のフリーダイヤルが「電話番号の形式が正しくありません」で弾かれる。

体験デモ:同じ番号を「携帯だけを想定したチェック」と「現実的なチェック」に通す

携帯のみ想定のチェック(0X0+11桁)-
現実的なチェック(0始まり10〜11桁)-

なぜ起きるか

日本の電話番号は種類によって長さが違います。固定電話は10桁、携帯(090/080/070)とIP電話(050)は11桁、0120のフリーダイヤルは10桁。 「会員登録するのは個人=携帯を持っているはず」という想定でチェックを書くと、固定電話しか持たない人、代表番号で登録したい法人、連絡先に0120を書きたい事業者が全員エラーになります。

正しい実装

// 直してから、最小限のチェック
const digits = value.normalize('NFKC').replace(/[^0-9]/g, '');
// 固定10桁・携帯/050は11桁・0120は10桁 → 「0始まりの10〜11桁」で受ける
if (!/^0\d{9,10}$/.test(digits)) {
  // ここで初めてエラー(国際表記 +81 を受けるならその分岐も)
}
// 「その番号で本人に届くか」が要件なら、本検証はSMS認証・折り返しで行う

桁数を厳密に縛りたくなったら、B章のメールと同じ問いを立ててください――その番号に実際に連絡する要件はありますか? あるならSMS認証や折り返しが本検証で、形式チェックの厳しさは要りません。

現実の被害

B2Bフォームでこれをやると、会社の代表番号(固定10桁)で問い合わせようとした見込み客が入口で止まります。携帯番号を書く文化のない企業の総務・情シスは、そこで諦めるか、仕方なく個人の携帯を書くことになります。

C-02

ハイフン・スペース・全角数字は「エラー」ではなく「直せる入力」

症状:「ハイフンなしの半角数字で入力してください」――連絡先アプリからのコピペや全角入力が突き返される。

体験デモ:弾くフォーム vs 直すフォーム

弾くフォームの応答(半角数字のみ許可)-
直すフォーム(正規化)の結果-

なぜ起きるか

電話番号の表記ゆれ――ハイフンの有無・全角/半角・スペース区切り――は、すべて機械が1行で吸収できる違いです。 しかも「全角のハイフン」には −(マイナス)・ー(長音)・―(ダッシュ)など複数の字があり、人間には見分けがつきません。「ハイフンは半角で」という指示は、人間に不可能な区別を要求しています(E章の全角強制とも同根の問題です)。

正しい実装

<!-- 入力の時点でスマホに数字キーボードを出す -->
<input type="tel" inputmode="numeric" autocomplete="tel" />

// ハイフン(半角/全角/長音/ダッシュ)・スペース・全角数字は全部機械が吸収する
const digits = value.normalize('NFKC').replace(/[^0-9]/g, '');
// 「090-1234-5678」も「090 1234 5678」も →「09012345678」

現実の被害

スマホの連絡先アプリからコピペした番号はスペースやハイフン入りが普通です。それを弾く=「手で打ち直せ」であり、モバイルのフォームで最も離脱を生む種類の摩擦です。しかも打ち直しはコピペより間違えます――誤入力を防ぐはずのチェックが、誤入力を増やしているのです。

D住所・郵便番号

日本の住所は「都道府県・市区町村・丁目・番地・号」の型に収まる――その前提自体が崩れている地域が実在します。住所欄の設計は、日本の住所制度の多様性との勝負です。

D-01

「1-2-3」と「一丁目2番地3号」は同じ場所 ―― 番地の表記ゆれ

症状:同じ住所なのに書き方が違うだけで「別の住所」として扱われ、重複登録・配送照合ミス・本人確認の不一致が起きる。

体験デモ:登録済み住所「1-2-3」と、あなたの入力を突き合わせる

単純な文字列一致での突合-
正規化してから突合(簡易再現)-

※デモの正規化は漢数字・区切り語・ハイフン類だけを吸収する簡易版です。実際の住所正規化はもっと奥が深い(だからこそ自前で書かない、が本エントリの結論です)。

なぜ起きるか

日本の住所には公式の「正規形」が事実上存在せず、「1-2-3」「1−2−3」「一丁目2番地3号」「1丁目2番3号」はすべて正しい書き方です。 人間は同じ場所だと分かりますが、文字列としては全部別物。これが重複顧客の温床であり、住所を突合するあらゆる業務(配送・名寄せ・本人確認)の古典的な難所です。

正しい実装

// 住所の表記ゆれ吸収を、自前の正規表現で頑張らない
// 実績のあるOSSや住所正規化サービスに寄せるのが現実解
// 例:geolonia/normalize-japanese-addresses(オープンソース)
const r = await normalize('京都府京都市中京区寺町通御池上る上本能寺前町488');
// → 都道府県・市区町村・町字・番地に構造化して返してくれる

// 自前でやるのは「比較の前にNFKC正規化+空白除去」程度に留める

入力欄の設計としては「表記ゆれをエラーにしない」が第一原則。どの書き方でも受け取り、揃える処理はシステム側の責務にする。

現実の被害

「ご登録の住所と一致しません」で本人確認に落ちる、同一人物が別顧客としてカウントされてDM二重送付――住所ゆれの被害は入力時ではなく、あとから業務側に出ます。

D-02

郵便番号→住所補完は「便利機能」であって「検証」ではない

症状:実在する郵便番号なのに「郵便番号が正しくありません」と言われる。補完された住所が実際と違う。

体験デモ:郵便番号補完の3つのシナリオ

住所辞書の応答-
「辞書ヒット必須」フォームの挙動-

※シナリオの再現デモです(実際の郵便番号データベースは同梱していません)。

なぜ起きるか

郵便番号辞書は「町域」を引くためのものですが、現実には例外が多くあります。大口事業所には個別の郵便番号が割り当てられており(全国に約2万件規模)、通常の町域辞書に無いか、辞書によって収録が異なります。新設の番号や辞書の更新遅れもある。 つまり「辞書にヒットしない=不正な郵便番号」ではありません

正しい実装

// 郵便番号は「直してから」チェック。住所補完は「提案」に留める
const zip = value.normalize('NFKC').replace(/[^0-9]/g, '');
if (!/^\d{7}$/.test(zip)) {
  // ここで初めてエラー(ハイフン有無・全角はこの時点で吸収済み)
}
// 補完した住所は必ず編集可能にする。
// 大口事業所の個別番号・新設番号・辞書の更新遅れがあるため、
// 「辞書にヒットすること」を登録の必須条件にしない

現実の被害

大口事業所番号を使う企業の担当者(=B2Bの発注元)が、自社の正式な郵便番号で登録できない。補完が「提案」ではなく「強制」だと、正しい住所を知っている本人が直せません。

D-03

京都の住所には「通り名」がある ―― 定型欄に入らない正式住所

症状:「寺町通御池上る」のような通り名を書く欄がなく、書けば文字数制限に当たり、省けば正式な住所ではなくなる。

体験デモ:京都市役所の所在地を「住所欄(20文字まで)」に入れる

入力の文字数-
20文字制限の欄に保存される値-

なぜ起きるか

京都市の中心部では「寺町通御池上る」のように、通りとの位置関係で場所を示す表記が正式に使われています。当然、住所は長くなります。 「町名は10文字程度」「番地欄は20文字もあれば十分」という感覚値で文字数制限を切ると、京都の正式住所は入りません。しかも京都には同じ町名が複数の区に存在するため、通り名を省くと特定性が下がる場合があります。

正しい実装

住所欄の文字数制限は「想定の2倍」ではなく、制度上あり得る長さから決める(都道府県から建物名まで含めれば100文字を超える住所は普通に存在します)。欄を分割する場合も、通り名・字(あざ)・方書きの置き場を潰さない。A-05(氏名の文字数)と同じ話です――制限の根拠を言えないなら、その制限は不要です

現実の被害

京都市中心部の事業者・住民が正式住所で登録できない。切り詰められた住所は配送・請求書送付の事故になり、「住所が変です」の問い合わせ対応コストとして返ってきます。

D-04

「丁目・番・号」が存在しない住所 ―― 分割欄の破綻

症状:丁目・番・号の3分割欄(各必須・数字のみ)に、丁目のない住所の人が入力できない。

体験デモ:丁目・番・号がすべて必須のフォーム

なぜ起きるか

「丁目・番・号」は住居表示が実施された市街地の型です。地方には「大字+番地」だけの住所が広くあり、北海道の農村部には「西5線北12号」のような線・号で表す住所も実在します。 都市部の住所の型を全国に強制する設計は、A-04(姓名分割の強制)と同じ構造の思い込みです。

正しい実装

住所の細部を構造化して受けたい要件(配送の機械処理など)が本当にあるか、まず疑う。多くのフォームでは「市区町村まで」+「それ以降は自由記述1欄」で足ります。構造化が必要でも、丁目・番・号を必須にしない。

現実の被害

該当地域の住民は毎回、欄のどこかに嘘(ダミーの「1」など)を書いて通すことになります。フォームが嘘の入力を強制している――バリデーションの目的と真逆の結果です。

D-05

郵便番号のハイフン・全角も「直せる入力」

症状:「123-4567」と入れると「ハイフンなしで」と怒られ、「1234567」と入れると「半角で」と怒られる。

体験デモ:弾くフォーム vs 直すフォーム

弾くフォームの応答(7桁半角数字のみ許可)-
直すフォーム(正規化)の結果-

なぜ起きるか

郵便番号の公式表記はそもそも「123-4567」のハイフン付きです。ハイフンを弾くフォームは、正式な書き方をエラーにしていることになります。全角はB-04・C-02と同じ話で、NFKC正規化1行の問題。

正しい実装

ハイフン・全角を吸収してから7桁チェック(コードはD-02のスニペット参照)。inputmode="numeric" で数字キーボードを出し、autocomplete="postal-code" でブラウザの自動入力を活かす。そして辞書ヒットを必須にしない(D-02)。

現実の被害

郵便番号はほぼ全フォームにある入力欄=この摩擦は全ユーザーが通る道です。ハイフン許容と正規化だけで、フォーム全体の離脱が目に見えて変わる箇所でもあります。

E文字と正規化

この大全の中核思想はここにあります――全角/半角のような「機械が直せる違い」を、人間へのエラーにしない。どちら向きの変換も1行で済むのに、フォームは今日も「全角で」「半角で」と人間に注文をつけています。

E-01

全角英数・㈱・半角カナは「エラー」ではなく「直せる入力」―― NFKC正規化

症状:「半角で入力してください」「機種依存文字は使えません」――機械が1行で直せる違いを、人間に直させている。

体験デモ:NFKC正規化で何が起きるか

NFKC正規化の結果-
入力との差-

なぜ起きるか

全角の「A」と半角の「A」、「㈱」と「(株)」、半角カナと全角カナ――これらはUnicodeが互換文字として対応関係を定義済みで、NFKC正規化という標準機能1つで機械的にそろえられます。それをやらずに「半角で入力してください」と表示するのは、システムの仕事を人間に外注しているだけです。

正しい実装

// 「入力の掃除」はこの3行を1回通すだけ
const clean = value
  .normalize('NFKC')                        // 全角英数・㈱・半角カナ等を正規化
  .replace(/[\u200B-\u200D\uFEFF]/g, '')    // ゼロ幅文字・BOMを除去
  .trim();                                  // 前後の空白・改行を除去
// そのうえで「本当に必要な検証」だけを行う

この「掃除3行」を検証の前段に入れるだけで、本大全のE章・B-04・C-02・D-05の問題はまとめて消えます。正規化結果は入力欄に反映して本人にも見せるのが親切です。

現実の被害

全角/半角エラーはあらゆるフォームで最も頻繁に出るエラーの一つ。1回のエラーで直してくれる人ばかりではありません――「なにが悪いのか分からない」まま離脱した人は、計測にすら残りません。

E-02

「全角で入力してください」の強制 ―― 逆方向も同じ問題

症状:住所や氏名の欄で半角数字を打つと「全角で入力してください」。しかも「全角ハイフン」には見分けのつかない亜種があり、正解の字を引き当てるまで怒られ続ける。

体験デモ:「番地は全角で」フォーム(数字は0-9・ハイフンは「-」のみ許可)

全角のみチェック-
様式チェック(ハイフンは「-」のみ)-

なぜ起きるか

E-01の逆方向です。固定長の基幹システムや帳票の都合で「保存形式は全角」という要件自体はあり得ます。問題は、その変換を入力者にやらせること。 「-(全角ハイフン)」「ー(長音)」「−(マイナス)」「―(ダッシュ)」は画面上ほぼ同じ見た目で、どれを打ったかを人間が制御することはできません。IMEの気分次第です。

正しい実装

保存形式が全角必須でも、受けるのはどの書き方でもよい。半角で来たら全角へ、亜種ハイフンは正規の字へ、システム側で変換する(E-01の逆写像を書くだけ)。「全角で入力してください」というエラーメッセージが必要になった時点で、設計が間違っています。

現実の被害

「見た目は同じなのに怒られ続ける」は、ユーザーが自力で脱出できない最悪のループです。行政・金融系フォームの離脱と電話問い合わせの定番原因でもあります。

E-03

「フリガナは半角カタカナで」―― 全銀フォーマットの亡霊

症状:普通に全角カタカナで打ったフリガナが「半角カタカナで入力してください」で弾かれる。

体験デモ:「半角カナのみ」のフリガナ欄

半角カナ強制チェック-
参考:NFKC正規化すると-

なぜ起きるか

正体は銀行振込のデータ形式(全銀フォーマット)など、半角カナ時代の固定長システムの要件が、Webフォームまで漏れ出してきたものです。 皮肉なことに、半角カナはUnicodeの世界では互換文字=NFKC正規化すると全角に戻る存在で、システム間を渡るたびに化ける危険を抱えています。人間に打たせる字としては最も不適格な部類です。

正しい実装

入力は全角カタカナ(またはひらがな)で受け、半角カナが必要な下流システムへはシステム側が変換して渡す。E-02と完全に同じ結論です――様式の都合を入力者に見せない。

現実の被害

スマホのキーボードで半角カナを出す方法を知らない人は大勢います(そもそも標準では出しにくい)。「半角カナで」の一文は、その全員への離脱ボタンです。

E-04

見えない「不正な文字」―― ゼロ幅スペースのコピペ混入

症状:見た目は完全に正しいのに「使用できない文字が含まれています」。ユーザーには直しようがない。

体験デモ:見た目が同じ2つの入力

見た目-
length-
不可視文字の検出-

なぜ起きるか

Webページやチャットからのコピペには、ゼロ幅スペース(U+200B)やBOMなどの不可視文字が混ざることがあります。見た目は同一、文字列としては別物。 これを「不正な文字が含まれています」とだけ言われても、ユーザーには見えないものを直せません

正しい実装

エラーにせず、黙って除去する(E-01の掃除3行に含めてあります)。不可視文字はユーザーの意図した入力ではないので、消しても情報は失われません。

現実の被害

本人には完全に正しく見えるため、「何度入力してもエラーになる」の問い合わせになります。サポート側も画面共有では見えないので、原因特定に時間を焼く厄介な障害です。

E-05

Macからコピペした「が」が一致しない ―― 濁点分離(NFD)

症状:見た目は同じ「がぎぐ」なのに、検索・突合で一致しない。文字数まで違う。

体験デモ:「がぎぐ」との比較

length-
「がぎぐ」との単純比較-
NFC正規化してから比較-

なぜ起きるか

「が」には2つの表現があります。合成済みの1文字(NFC)と、「か」+結合濁点の2文字(NFD)。macOSのファイル名などはNFD系で、そこからのコピペで分離形が紛れ込みます。 見た目は完全に同じ。lengthと比較結果だけが狂う――E-04と並ぶ「見えない不一致」の代表です。

正しい実装

// 文字列を比較する前にNFC正規化する
// (濁点分離「か+゛」を合成済みの「が」にそろえる)
const same = a.normalize('NFC') === b.normalize('NFC');

E-01の掃除でNFKC正規化を通していれば、この問題も同時に解決しています(NFKCはNFCの合成を含みます)。

現実の被害

顧客名簿の名寄せ・検索のヒット漏れとして静かに効いてきます。「登録があるはずの顧客が検索で出てこない」の一因です。

E-06

〜と~は別の字 ―― 波ダッシュ問題という古典

症状:「10:00〜18:00」の「〜」が化ける・一致しない。正規化してもそろわない。

体験デモ:どちらの「なみ」が使われているか

検出された「なみ」-
NFKC正規化すると-

なぜ起きるか

日本語環境の歴史的事情で、「〜」には波ダッシュ(U+301C)と全角チルダ(U+FF5E)の2つが混在しています。WindowsのIMEは伝統的に全角チルダを、他の多くの環境は波ダッシュを出します。 厄介なのは、NFKC正規化でも統一されないこと。波ダッシュはそのまま残り、全角チルダは半角の「~」になって、むしろ遠ざかります。E章で唯一「正規化では救えない」問題です。

正しい実装

// 波ダッシュはNFKCでも統一されない:
//   〜(U+301C 波ダッシュ)→ そのまま残る
//   ~(U+FF5E 全角チルダ)→ ~(半角チルダ)になり、むしろ遠ざかる
// 日本語テキストの突合では明示的に置換するしかない
const unified = value.replace(/\uFF5E/g, '\u301C'); // ~ → 〜

現実の被害

検索・突合のヒット漏れ、古いシステムとの連携での文字化け。「営業時間の『〜』が?に化けている」を見たことがあれば、それがこの問題です。

E-07

末尾のスペース1個で弾かれる ―― trimしないフォーム

症状:コピペやキーボードの予測変換で紛れた前後の空白・改行のせいで、正しい入力が「形式エラー」になる。

体験デモ:メール欄に「末尾スペース付き」で入力する

trimしないフォームの応答-
trimするフォームが受け取る値-

なぜ起きるか

スマホの予測変換は確定時にスペースを足すことがあり、コピペは改行や前後の空白を巻き込みます。ユーザーはその存在に気づけません。 前後の空白は入力の意図に含まれない――だから黙って落とすのが正解で、わざわざエラーにする情報価値がありません。

正しい実装

検証の前に .trim()(E-01の掃除3行の3行目)。ただしパスワード欄だけは例外で、空白が意図的な場合があるためtrimせず、代わりに「前後に空白が入っています」と教えるのが親切です。

現実の被害

「メールアドレスが正しくありません」の問い合わせの一定割合は、これです。見えない1文字のために、正しいアドレスの持ち主を追い返しています。

F日付・数値・金融系

日付と金額は「機械が得意なはず」の領域なのに、和暦・存在しない日付・カンマ入り金額と、日本語フォームの罠が集中しています。共通する解は他章と同じ――直せるものは直し、解釈は本人に見せる

F-01

和暦の罠 ―― 「元年」と「1年」、そして昭和100年

症状:「令和元年」と「令和1年」が別物として扱われる。改元のたびにシステム改修が発生する。存在しないはずの「昭和100年」が計算だけ通ってしまう。

体験デモ:和暦→西暦テスター

西暦への換算-
その元号年は実在するか-

なぜ起きるか

和暦には「元年か1年か」の表記ゆれ、改元のたびの改修、そして存在しない元号年が機械的な足し算では通ってしまう問題があります。 「昭和100年」は実在しませんが、昭和ベースの2桁年でデータを持ち続けた古いシステムでは1925+100=2025年として計算だけは成立します。2025年が実際に「昭和100年」に到達し、昭和100年問題として現実の点検対象になりました。

正しい実装

内部表現と保存は西暦(ISO 8601)に統一し、和暦は表示層だけの仕事にする。入力で和暦を受けるなら「元年」表記を受け付け、元号の有効範囲(昭和は64年まで等)を検証する。改元対応が「表示文言の追加」だけで済む構造にしておくのが正解です。

現実の被害

生年月日の和暦入力は行政・金融・医療系で現役です。「元年」と「1年」の突合ゆれは名寄せミスに、内部の和暦依存は改元のたびの改修費に化けます。

F-02

2月30日が選べてしまう ―― 独立プルダウンとJSの静かな繰り越し

症状:年・月・日を別々のプルダウンにすると存在しない日付が選べる。しかもJSのDateは「2月30日」を黙って「3月2日」にする。

体験デモ:独立プルダウンで日付を選ぶ

JSのnew Date()に渡すと-
実在する日付か(ロールオーバー検知)-

なぜ起きるか

独立した3つのプルダウンは「その月に何日あるか」を知りません。そしてJavaScriptのDateは不正な日付をエラーにせず、黙って翌月へ繰り越します。「2月30日」と入力したユーザーのデータが「3月2日」として保存され、誰も気づかない――エラーより性質の悪い、静かなデータ破損です。

正しい実装

// 「存在する日付か」はロールオーバー検知で1発
const d = new Date(y, m - 1, day);
const valid = d.getFullYear() === y && d.getMonth() === m - 1 && d.getDate() === day;
// new Date(2026, 1, 30) は黙って「3月2日」になる——気づかずに通さない
// 内部表現・保存は西暦のISO 8601(YYYY-MM-DD)に統一する

プルダウンを使うなら月に応じて日の選択肢を絞る。未来/過去の範囲チェック(生年月日が来年、など)もここで。

現実の被害

実在しない生年月日は年齢計算・本人確認の突合でのちに発覚し、原因調査はいつも難航します。入口で1行のチェックを省いた代償です。

F-03

生年月日プルダウンの遠い旅 ―― 初期値と並び順の設計放棄

症状:年プルダウンの初期値が今年で、自分の生まれ年まで延々スクロールさせられる。

体験デモ:ダメな年プルダウン vs 数字入力

プルダウン:選択肢の上から-
数字入力:必要な打鍵-

なぜ起きるか

年プルダウンの初期値を今年にすると、生年月日入力では全ユーザーが数十項目先まで移動することになります。カレンダーUI(type="date")も月送りで生年月日には不向き。 「とりあえずプルダウン」は、選ぶ値が近くにある場合の道具です。生年月日はそうではありません。

正しい実装

生年月日は数字の直接入力(YYYY/MM/DD・inputmode="numeric")+autocomplete="bday"が最速です。ブラウザの自動入力が効けば0打鍵で終わる。プルダウンを使うなら、せめて並びと初期値を利用者の分布に合わせて設計する。

現実の被害

年齢確認が必要なサービスでは全員が通る道=小さな摩擦×全ユーザーで、登録フォームの離脱率にそのまま乗ります。

F-04

「1,000」「1000」「1万」を弾くな ―― 金額欄の貧しい正規表現

症状:カンマ付き・全角・「万」単位の金額が「半角数字で入力してください」で突き返される。

体験デモ:弾くフォーム vs 直すフォーム(予算欄)

弾くフォームの応答(半角数字のみ許可)-
直すフォームの解釈-

なぜ起きるか

カンマ区切りは経理・Excelの標準表記、全角はIMEの標準状態、「万」は日本語の自然な金額単位。つまり弾かれている入力は全部、書いた本人にとって最も自然な書き方です。 ただし「万」の解釈には誤読リスクもあるので、変換は黙ってやらず、解釈結果を表示して本人に確認させるのが作法です。

正しい実装

// 金額は「直して、解釈を見せて、確認してもらう」
const n = Number(
  value.normalize('NFKC')
       .replace(/[,,円\s]/g, '')
       .replace(/^(\d+)万(\d{1,4})?$/, (_, man, rest) => String(man * 10000 + Number(rest || 0)))
);
// 「1,000」「1000」「1万」「3万5000」→ 1000 / 1000 / 10000 / 35000
// 解釈した金額を画面に表示して本人に確認させる(黙って変換だけしない)

現実の被害

「ご予算」欄はB2Bの見積もり・問い合わせフォームの定番項目。ここで弾かれた見込み客の気持ちを想像してください――予算を伝えようとして、書式で怒られたのです。

Gバリデーション設計の作法

最終章は個別の文字や形式ではなく、フォームの振る舞いそのものの話。ここに並ぶのは「最も憎まれているフォームの挙動」たちです。検証ロジックが正しくても、振る舞いが悪ければフォームは人を追い返します。

G-01

「入力が不正です」しか言わないエラーメッセージ

症状:何が・どこが・どうすれば直るのか、何も教えてくれない。ひどい場合はエラーコードの番号だけ。

体験デモ:同じ入力ミスに対する3種類のエラーメッセージ

ダメな例①-
ダメな例②-
良い例-

なぜ起きるか

エラーメッセージが「検証に失敗した」という実装側の事実の記録になっていて、「どうすれば成功するか」というユーザーへの案内になっていないためです。 良いエラーメッセージの3要素は「何が・どこで・どうすれば」。この3つが揃わないメッセージは、書き直しです。

正しい実装

エラーは該当フィールドの直下に表示し、aria-describedbyで入力欄と関連付ける(スクリーンリーダーにも届く)。文言は「メールアドレスに使えない文字「,」が5文字目にあります」のように、位置と直し方まで言う。エラーコードを出すなら、必ず人間向けの説明を併記する。

現実の被害

「何が悪いのか分からない」ユーザーは2〜3回試して離脱します。エラーメッセージの質は、フォームの完了率に直結する数少ないコピーライティングです。

G-02

入力途中で怒るな ―― リアルタイム検証のタイミング

症状:メール欄に「t」と打った瞬間から「形式が正しくありません」と赤く怒られ続ける。

体験デモ:2つの欄に、実際にメールアドレスを打ってみてください

※良い欄は入力中に新しく怒りません。いったんエラーになった後も、入力中の再検証は「エラーを消す方向」にだけ働きます(直った瞬間・消した瞬間に赤が消える)。

なぜ起きるか

「リアルタイム検証は親切」という half-truth のためです。親切なのは直したことをリアルタイムに認めてくれる検証であって、書き終わる前に不合格を宣告する検証ではありません。

正しい実装

原則は「新たに怒るのはblur(欄を離れたとき)だけ。入力中の再検証は、エラーを消すためにだけ使う」。エラーは遅く出して、早く消す。送信時には全体を再検証し、最初のエラーにフォーカスを移す。

現実の被害

入力中の赤エラーはユーザーの作業記憶に割り込みます。「怒られながら書くフォーム」の完了率が下がるのは、体感の通りです。

G-03

確認用欄の「貼り付け禁止」という愚行

症状:メールアドレス(確認用)にペーストできず、長いアドレスをもう一度手打ちさせられる。パスワードマネージャーも動かない。

体験デモ:下のボタンでアドレスをコピーして、2つの欄に貼り付けてみてください

なぜ起きるか

「コピペだと確認にならないから」という理屈ですが、逆です。確認欄が防ぎたいのはタイプミス。貼り付け禁止は、2回目のタイプミスの機会を増やしているだけです。 パスワード欄での貼り付け禁止に至っては、英国NCSC(国家サイバーセキュリティセンター)が「貼り付けを許可せよ」と公式に呼びかけているほどの、セキュリティ上も逆効果な慣習です(パスワードマネージャーの利用を妨げるため)。

正しい実装

貼り付けを禁止しない。そもそも確認用欄の必要性を疑う――メールはダブルオプトイン(B-02)があれば確認欄は不要、パスワードは表示切替ボタン付きの1欄で足ります。

現実の被害

長いメールアドレス・強力なパスワードほど手打ちがつらい=セキュリティ意識の高いユーザーほど痛めつける設計になっています。

G-04

エラーで入力が全部消える ―― 最も憎まれている挙動

症状:長文を書いて送信したらエラー。戻ったら全部消えていた。

体験デモ:15分かけて書いた問い合わせを送信する

なぜ起きるか

サーバーでエラーになった際、入力値を持たずにフォームを再描画しているためです。ほかにも確認画面からの「戻る」・セッションタイムアウト・ページリロードなど、入力が消える経路は複数あります。 入力値の保持は、フォームを返す側の責務です。ユーザーの15分を預かっている自覚の問題とも言えます。

正しい実装

エラー時は入力値を保持して返す(主要フレームワークは全部標準機能で持っています)。長文欄はさらに、下書きの自動保存(localStorage等)で リロード・タイムアウトからも守る。

現実の被害

消えた長文を書き直す人は少数派です。問い合わせ・応募・レビュー投稿――長文を書いてもらうフォームほど、この一撃で見込み客ごと失います

G-05

「ブラウザの戻るボタンは使用しないでください」

症状:うっかり戻るを押すと「不正な遷移です」。入力は全部消え、注意書きの赤文字だけが増えていく。

体験デモ:2ステップフォームの再現(実際の履歴は操作しません)

なぜ起きるか

画面遷移をサーバーセッションの一本道として設計し、ブラウザの履歴という現実と衝突しているためです。 「戻るボタンを使わないでください」という注意書きは、Web標準の否定をユーザーへのお願いで乗り切ろうとする様式美であり、注意書きが必要になった時点で設計は負けています。

正しい実装

戻るを壊さない設計にする――各ステップに戻っても入力が保持される状態管理、POST後のリダイレクト(PRGパターン)で再送信ダイアログも防ぐ。ユーザーの「戻りたい」は自然な欲求で、禁止ではなく設計で受け止めるものです。

現実の被害

G-04と合わせ技で発動することが多く、行政・金融系の長大なフォームでの離脱・電話問い合わせの定番原因です。

G-06

HTMLにできる仕事をJSで壊すな ―― type・inputmode・autocomplete

症状:スマホでメール欄なのに日本語キーボードが出る。ブラウザが覚えている住所が自動入力されない。全部 type="text" と autocomplete="off" のせい。

属性チートシート:欄の種類を選ぶと、実物の欄と推奨マークアップが出ます

スマホで開くと、種類に応じてキーボードが切り替わります。ブラウザに保存された住所・連絡先があれば自動入力候補も出ます。

なぜ起きるか

ブラウザは無料でキーボードの切替(type/inputmode)と自動入力(autocomplete)を提供しています。それを使わず全欄type="text"で作り、挙句にautocomplete="off"を乱発してブラウザやパスワードマネージャーの支援を殺す――フォームの体験を無償で良くする機能を、わざわざ無効化しているのです。

正しい実装

上のチートシートの通り。原則は「まずHTMLに仕事をさせる。JSは補助」。本大全のE-01(掃除3行)とこのチートシートを合わせれば、日本語フォームの土台はほぼ完成します。

現実の被害

スマホでのキーボード切替は1欄あたり数秒×全ユーザーの摩擦。自動入力が効くフォームと効かないフォームでは、体感の「軽さ」がまるで違います――そしてユーザーはその理由を言語化できないまま、重いフォームを嫌います。

テスト文字列バッテリー

本大全のエントリから抽出した「この入力、通りますか?」のコピペ集(全36件)。あなたのフォームに貼って、挙動を確かめてください。 実在の連絡先に届かない設計です(メールは予約ドメイン等・電話は例示番号のみ)が、テストは自社システムの検証環境で行うのが作法です。

氏名・人名

𠮷野家 サロゲートペア(.lengthが4になる)
髙﨑 彅 JIS X 0208外の拡張字+スペース
渡邊𠮷彅 拡張字とBMP外の混在
1文字の姓
グリゴリー・アレクサンドロヴィッチ 長い名前・中黒入り
ジョン スミス カタカナ+スペース
みなみ 単名(姓と名に分割できない)

メールアドレス

example..demo@docomo.ne.jp 連続ドット(ドコモ旧仕様の形式)
example.demo.@docomo.ne.jp @直前ドット(同上)
taro+tag@gmail.com プラスエイリアス
taro@example.com 全角
taro@example.engineering 4文字を超えるTLD
taro@example.com 末尾に半角スペース

電話番号

090-1234-5678 全角数字+全角ハイフン
090 1234 5678 スペース区切り(連絡先アプリからのコピペ)
03-1234-5678 固定電話(10桁)
050-1234-5678 IP電話
0120-123-456 フリーダイヤル(10桁)

住所・郵便番号

京都府京都市中京区寺町通御池上る上本能寺前町488 通り名入りの正式住所(京都市役所)
一丁目2番地3号 漢数字・単位語の番地表記
1−2−3 全角数字+全角マイナス記号
123-4567 郵便番号の公式表記(ハイフン付き)
1234567 郵便番号の全角入力

文字と正規化

㈱アクシア 組文字(NFKCで「(株)」になる)
アクシア 半角カタカナ
アク​シア ゼロ幅スペース入り(見た目は普通の「アクシア」)
がぎぐ 濁点分離(NFD・見た目は「がぎぐ」)
10:00〜18:00 波ダッシュ(U+301C)
10:00~18:00 全角チルダ(U+FF5E)
1ー2ー3 長音記号をハイフンのつもりで入力

日付・数値

令和元年 「元年」表記
昭和100年 実在しない元号年(換算だけは通る)
2026/02/30 存在しない日付
1,000 カンマ区切りの金額
1000 全角の金額
3万5000 「万」単位の金額

JSONは category / value / note の配列です。GitHubでの配布リポジトリも準備中。バッテリーはエントリの追加とともに育てていきます。

このページは更新し続けます

本ページは一度きりの記事ではなく、更新し続ける正典(リファレンス)として運営します。エントリの追加候補・内容の誤りはお問い合わせからお寄せください。

このページは、東京のシステム開発会社 株式会社アクシア が運営しています。私たちは自社サイトのフォーム改善で「入力開始した人の約9割がフォームで離脱していた」という実データと向き合った経験から、このリファレンスを作りました。 内容の誤りに気づいた方はお問い合わせからご指摘ください。確認のうえ更新します。