技術資料

PHPでフリガナ欄の入力を検証する:全角ハイフン・長音・カタカナの扱い

作成日:2026.11.11

住所のフリガナ欄で、全角ハイフンを入力したつもりなのにエラーになることがあります。見た目が似たハイフンや長音の違いを確認し、PHPでカナや英数字を変換してから検証する方法を紹介します。入力を保持したエラー表示や、変換後の値を確認する方法も解説します。

フォームのフリガナ欄について、「全角ハイフンを入力しているのにエラーになる」という問い合わせには、これまで何度も対応してきました。利用者から見ると同じような横棒でも、プログラムから見ると別の文字になっていることがあります。

こうした入力を受け付けやすくするには、正規表現の許可範囲だけでなく、どの文字を同じものとして扱い、どの形にそろえてから検証するかを決めておく必要があります。今回は住所のフリガナ欄を例に、PHPでの実装方法を整理します。

例に使う住所と文字制約は説明用です。PHP 8.3.15 CLI、PCRE2 10.42、mbstring・intl拡張を有効にした環境でコードを確認しています。

「全角」だけでは、許可する文字が決まらない

まず、よく使う文字範囲を整理しておきます。次のパターンは、UTF-8の文字列全体が指定した範囲の文字だけで構成されているかを確認するものです。

対象パターン例範囲に含めていない文字
ひらがなの基本的な範囲/\A[ぁ-ゖ]+\z/u長音、繰り返し記号、結合濁点など
カタカナの基本的な範囲/\A[ァ-ヺ]+\z/u長音、中黒、半角カナなど
全角英字/\A[A-Za-z]+\z/u半角英字など
全角数字/\A[0-9]+\z/u半角数字など

\Aと\zは文字列全体の先頭と末尾、uはUTF-8として扱う指定です。詳しくはPHPの正規表現で日本語・改行を扱う記事で紹介しています。

この表は、あらゆる日本語の入力欄に使えるパターンというわけではありません。例えば、カタカナの範囲だけでは「コーポ」の長音ーも通りません。必要なら[ァ-ヺー・]のように、長音や中黒を明示的に追加します。

Unicodeプロパティを使う方法もありますが、例えば\p{scx:Katakana}は「全角カタカナだけ」という条件ではなく、半角カナも対象になります。

似た横棒をコードポイントで見分ける

ハイフンや長音も、見た目だけで区別するのは難しいところです。次の文字は、それぞれコードポイントが異なります。

文字コードポイントUnicode上の名称
-U+002DHYPHEN-MINUS
-U+FF0DFULLWIDTH HYPHEN-MINUS
‐U+2010HYPHEN
‑U+2011NON-BREAKING HYPHEN
−U+2212MINUS SIGN
―U+2015HORIZONTAL BAR
ーU+30FCKATAKANA-HIRAGANA PROLONGED SOUND MARK

原因を調べるときは、問題の文字を1文字ずつ確認すると切り分けやすくなります。以下の文字列は説明用です。

$text = '-−ー';
foreach (mb_str_split($text, 1, 'UTF-8') as $char) {
    printf("%s U+%04X\n", $char, mb_ord($char, 'UTF-8'));
}
// - U+FF0D
// − U+2212
// ー U+30FC

住所のフリガナ欄で、何を受け入れるか決める

今回は、町名の読み、番地、建物名を一つの欄に入力する想定にします。文字の種類だけを確認する例で、住所の存在や番地の正しさを検証するものではありません。

入力今回の扱い
ひらがな・半角カナ全角カタカナへ変換する
結合濁点・半濁点NFCで合成できるものを合成する
全角英数字半角英数字へ変換する。建物名の英字も許可する
全角スペース半角スペースへ変換する。前後の半角スペースは除く
- ‐ ‑ −区切りとして受け入れ、半角の-へそろえる
長音ー・中黒・そのまま保持する
上記以外の記号・漢字・改行など削除せず、修正を案内する

保存形式を半角英数字にするのは、今回の仮要件です。利用者には「全角のみ」と案内せず、「ひらがな・半角カナも入力できます。英数字と番地のハイフンは半角にそろえます」のように、実際の処理を伝えるほうが親切でしょう。

ハイフン類をすべて長音へ置き換えるのは避けます。例えばコーポ 1-2の長音と番地の区切りは役割が異なります。氏名のフリガナ欄なら、数字や番地の区切りを受け入れる必要があるかも別に考える必要があります。

数字の間に長音がある1ー2は、区切りを入力した可能性があります。ただし、勝手に置換してしまうのも悩ましい。こうした判断も、入力欄ごとに決めておきたいところです。

文字をそろえてから、PHPで検証する

処理は「型・サイズ・文字コードの確認 → 必要な変換 → 変換後の検証」の順にします。今回使うmb_convert_kana()のモードは、Kが半角カナ、Vがその濁点の合成、Cがひらがな、rが全角英字、nが全角数字、sが全角スペースの変換です。

さらに、結合濁点などをNFCで合成します。NFKCは丸数字なども変換するため、今回の例では採用しません。また、NFCでもNFKCでも、似た横棒がすべて同じ文字になるわけではありません。ハイフンの対応表は別に用意します。

function validateAddressKana(mixed $raw): array
{
    if (!is_string($raw)) {
        return ['value' => null, 'error' => '住所のフリガナを文字列で入力してください。'];
    }
    if (strlen($raw) > 4096) {
        return ['value' => null, 'error' => '入力が長すぎます。'];
    }
    if (!mb_check_encoding($raw, 'UTF-8')) {
        return ['value' => null, 'error' => '文字コードが不正です。'];
    }

    $value = mb_convert_kana($raw, 'KVCrns', 'UTF-8');
    $value = Normalizer::normalize($value, Normalizer::FORM_C);
    if ($value === false) {
        throw new RuntimeException('Unicode正規化に失敗しました。');
    }

    $value = strtr($value, [
        "\u{FF0D}" => '-', // 全角ハイフンマイナス
        "\u{2010}" => '-', // ハイフン
        "\u{2011}" => '-', // 改行しないハイフン
        "\u{2212}" => '-', // マイナス記号
    ]);
    $value = trim($value, ' ');

    if ($value === '') {
        return ['value' => null, 'error' => '住所のフリガナを入力してください。'];
    }
    if (mb_strlen($value, 'UTF-8') > 200) {
        return ['value' => null, 'error' => '変換後のフリガナは200文字以内で入力してください。'];
    }

    // 許可範囲外の最初の文字を取得する。ハイフンは範囲指定と区別する。
    $result = preg_match('/[^ァ-ヺー・A-Za-z0-9 \-]/u', $value, $matches);
    if ($result === false) {
        throw new RuntimeException('正規表現の実行に失敗しました。');
    }
    if ($result === 1) {
        $codePoint = sprintf('U+%04X', mb_ord($matches[0], 'UTF-8'));
        return [
            'value' => null,
            'error' => "使用できない文字「{$matches[0]}」({$codePoint})があります。"
                . 'カナ・英数字・空白・中黒・ハイフンで入力してください。',
        ];
    }

    $result = preg_match('/[0-9]ー[0-9]/u', $value);
    if ($result === false) {
        throw new RuntimeException('正規表現の実行に失敗しました。');
    }
    if ($result === 1) {
        return [
            'value' => null,
            'error' => '数字の間に長音「ー」があります。番地の区切りなら「-」へ変更してください。',
        ];
    }

    return ['value' => $value, 'error' => null];
}

許可していない文字を検索し、一つでも見つかったら修正を案内しています。先ほどの表のように、許可文字だけで文字列全体が構成されるかを確認する方法でも構いません。今回はエラーになった文字を示すため、範囲外の文字を取得する形にしました。

trim($value, ' ')は前後の半角スペースだけを除きます。改行やタブを黙って消さず、検証で拒否するためです。上限は変換前が4096バイト、変換後が200コードポイントという仮の値で、保存先の容量などに合わせて調整してください。

この例は、ハイフンだけの入力や番地の並び順などを検査しません。許可文字を増やしただけで、住所として正しいと判断しないようにしましょう。また、[ァ-ヺ]に含まれない拡張カナなどが必要なサービスでは、対象文字を調べて要件を調整してください。

似た文字を含む入力で結果を確認する

前の関数を定義してから、例えば次のように実行できます。

$result = validateAddressKana('さくらちょう 1-2 コーポA');
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
// {"value":"サクラチョウ 1-2 コーポA","error":null}

主な確認結果は次のとおりです。表中の\u{...}、\nはPHPの二重引用符内で指定する文字の表記です。

入力例結果
さくらちょう 1-2 コーポAサクラチョウ 1-2 コーポAへ変換して受け入れる
サクラチョウ 1−2(U+2212)サクラチョウ 1-2へ変換して受け入れる
コーポ 1‐2(U+2010)コーポ 1-2へ変換。長音は保持する
コーポ 1‑2(U+2011)コーポ 1-2へ変換して受け入れる
カ\u{3099}ーテ\u{3099}ン 1-2(結合濁点)ガーデン 1-2へ変換して受け入れる
サクラチョウ 1ー2(長音)番地の区切りか確認する案内を返す
サクラチョウ 1―2(U+2015)今回の対応表にないため、該当文字を示して修正を求める
サクラチョウ ①丸数字を勝手に数字へ変換せず、修正を求める
サクラ\nチョウ、空白だけ、不正UTF-8それぞれ拒否する

今回拒否した―なども、サービスの入力実態と保存先の仕様によっては変換対象に追加できます。その際は、追加した文字のコードポイントと変換結果をテストへ残しておくと、後から理由を確認できます。

入力を保持し、変換した結果を確認できるようにする

エラー時に入力欄が空になると、利用者は住所を最初から入力し直すことになります。入力値を保持したうえで、どの文字を直せばよいかを表示します。通った場合も、保存前に変換後の値を確認できるようにしておくと安心です。

以下はフォーム処理へ組み込む部分の例です。前の関数を定義済みとし、受け取った値と検証結果を用意します。

$raw = $_POST['address_kana'] ?? '';
$result = validateAddressKana($raw);
$inputValue = is_string($raw) ? $raw : '';

function escapeHtml(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
<label for="address_kana">住所のフリガナ</label>
<p id="kana_help">ひらがな・半角カナも入力できます。英数字と番地のハイフンは半角にそろえます。</p>
<input id="address_kana" name="address_kana"
    value="<?= escapeHtml($inputValue) ?>"
    aria-describedby="kana_help kana_result">
<p id="kana_result">
<?php if ($result['error'] !== null): ?>
    <?= escapeHtml($result['error']) ?>
<?php else: ?>
    変換後:<?= escapeHtml($result['value']) ?>
<?php endif; ?>
</p>

これはPOSTを処理する場面の抜粋です。実際の画面では初回表示と送信後を分け、検証に通った値だけを保存処理へ渡します。予期しない例外はアプリ側で記録し、利用者へ内部情報をそのまま表示しないようにします。

HTMLへ表示する際のエスケープは、入力検証とは別に必要です。エラー文にも入力文字が含まれるので、同じようにエスケープします。ブラウザー側にpatternやJavaScriptの検証を追加する場合も、PHPが変換して受け入れる入力を先に拒否しないよう、規則をそろえてください。

今回確認したのはPHP側の変換・検証とテンプレートの出力です。IMEやスマートフォンごとの入力挙動はまちまちなので、実際のフォームでは対象端末でも確認しておきましょう。

まとめ

フリガナ欄の入力エラーを減らすには、「全角カタカナで入力してください」という案内だけで済ませず、似た文字をどう受け入れるかまで決めておくのがよいかと思います。

住所では、長音と番地の区切りを分け、必要な文字だけを変換してから検証する。自動で判断できない入力は、消さずに具体的な修正方法を案内する。この形にしておくと、利用者にも、問い合わせを受ける側にも分かりやすくなります。

参考資料

この記事を書いた人

※上が私です。

奈良市を拠点に、27年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。

これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。

【制作会社・企業様向けサポート】
  • 専任エンジニアのいない企業様に対するシステム面の不安を解消
  • 柔軟な契約形態や短納期での対応により、急なニーズにも迅速にサポート
  • システムの企画段階から運用まで、ワンストップでのサービスを提供

Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。

ぜひ、プロフィールやWeb制作会社様向け業務案内、一般企業様向け業務案内もご覧くださいね。

PHPの正規表現で日本語・改行を扱う:u・m・s修飾子の違い

2026.09.29

PHPの正規表現で日本語や複数行テキストを扱う際の、u・m・s修飾子の違いを解説します。Unicode文字クラスと全角数字、CRLFの行末処理、\A・\zの使い方、Unicode正規化との違いを、PHP 8.3.15・PCRE2 10.42で確認したコード例とともに紹介します。

PHP 正規表現

PHPの正規表現を使い分ける:preg_match・preg_match_all・preg_replaceと入力検証

2026.08.28

PHPのpreg_match、preg_match_all、preg_replaceを使い、一致した値の取り出し、複数箇所の抽出、文字列置換を行う方法を解説します。u修飾子やmb_check_encodingにも触れ、メールアドレスの形式検証では、正規表現やfilter_var()だけで到達性・所有確認まではできないことを説明します。

PHP 正規表現

perlとPHPで使える、フォーム入力のエラーチェックに役立つ正規表現集

2009.03.28

フォームからのデータ送信はWebアプリケーションの基礎ですが、ユーザーが入力する内容が想定通りであるかを確認するためのエラーチェックは重要です。この記事では、perlとPHPでフォームデータをバリデートするための正規表現を具体例とともに紹介します。

Perl PHP 正規表現

XAMPPのPHP更新時にphp.iniをどう移行する? 引き継ぐ設定と確認方法

2026.11.12

XAMPPでPHPを更新する際のphp.iniの移行方法を解説します。旧設定と新しい設定例を比較し、引き継ぐ項目や変更が必要な項目を整理。拡張・パス・エラー出力・アップロード・セッションなどの注意点と、CLI・Apacheそれぞれで設定の反映を確認する方法を紹介します。

PHP XAMPP

阿部辰也へのお仕事の依頼・お問い合わせ

軽いご相談もお気軽にどうぞ!

個人情報の取り扱いについて *必須 プライバシーポリシーをご確認いただき、同意いただける場合は「同意する」にチェックをしてください。

keyboard_double_arrow_up
TOP