PHPで郵便番号のハイフンがあってもなくてもハイフンありに変換する

入力フォームには、大抵「郵便番号入力欄」があります。
入力欄が3桁、4桁に分かれているものもありますが、入力欄が一つにまとまっている場合もあります。
入力制限をしていればどうということはありませんが、そうでない場合、入力される方によってハイフンがついていたり、ついていなかったりします。
フォーマットがばらばらだと、後から表示がおかしくなったりする原因にもなります。
厳密にやるならば、入力欄をギチギチに設定すればよいのですが、今回はあえて自由入力でPHPで自動でフォーマット統一する方法を作ってみました。
実際に作ってみたものがこちら

百聞は一見に如かず。
郵便番号を自動で統一化するサンプルを作ってみました。



ソースはこちらです。
<?php
$input_postno = null;
$output_postno = null;
if ((isset($_REQUEST["postno"]) == true)
&& (isset($_REQUEST["reset"]) != true))
{
$input_postno = $_REQUEST["postno"];
$msg = ;
$class = null;
/** 郵便番号チェック */
$sts = postno_chk($input_postno);
/** 郵便番号セット */
$postno = $sts["postno"];
if ($sts["sts"] != true)
{
/** エラーメッセージセット */
$msg = $sts["err"];
$class = " class='err'";
}
$date = date("Y-m-d H:i:s");
/** メッセージセット */
$output_postno = "<div${class}><p>${date}</p><p>${postno}</p><p>${msg}</p></div>";
}
functionpostno_chk($postno){
$sts = array("sts"=>false, "err"=>null, "postno"=>null);
/** 数字を半角に変換する */
$postno = mb_convert_kana($postno, "n");
/** 数字以外を削除する */
$postno = preg_replace("/[^0-9]/", "", $postno);
if (mb_strlen($postno) != 7)
{
/** エラーメッセージセット */
$sts["err"] = "郵便番号の桁数が正しくありません";
return $sts;
}
/** 郵便番号のフォーマット変換 */
$postno_01 = substr($postno, 0, 3);
$postno_02 = substr($postno, -4, 4);
$sts["postno"] = "${postno_01}-${postno_02}";
/** チェックOKセット */
$sts["sts"] = true;
return $sts;
}
?><!doctype html><html><head><metacharset="shift_jis"><title></title><styletype="text/css">section
{
text-align: center;
width: 600px;
margin-right: auto;
margin-left: auto;
padding-top: 20px;
padding-bottom: 20px;
border: 1px solid #ddd;
border-radius: 6px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
}
div
{
padding: 10px;
width: 80%;
border: 10px solid #0C0;
color: #0C0;
margin-right: auto;
margin-left: auto;
margin-top: 10px;
}
.err
{
border: 10px solid #F00;
color: #F00;
text-align: left;
}
</style></head><body><section><formaction=""method="post"enctype="multipart/form-data"><h1>郵便番号を入力してください</h1><p></p><inputname="postno"type="text"value="<?php echo $input_postno; ?>"style="width: 400px"><inputname="submit"type="submit"value="送信"><inputname="reset"type="submit"value="リセット"><?phpecho $output_postno ?></form></section></body></html>
Code language:HTML, XML(xml)
疑問:郵便番号のフォーマットを自動で統一化するにはどうすればいいの?

例えば郵便番号は「9391324」「939-1324」と2種類の入力をされた場合、まず何をすればよいのでしょうか?
なんとなく、「ハイフンが無ければハイフンを付け足す」と考えがちです。
でもそのやり方には欠点があります。
なぜならば、ハイフンを差し込む位置を間違えて入力していた場合など、に対応できないためです。
理想は数字さえ入力されていれば、どんな入力でも自動変換するです。
では、どうすればいいのでしょうか?
答:いったん数字に変換してからハイフンを付け足します

いったん数字のみに変換することで、あとからどのようにでもフォーマットを変換できます。
サンプルもまずは、数字のみに変換しています。
数字のみへ変換する方法
では数字だけに変換するにはどうすればよいでしょうか?
実は1行で変換できます。
それがこちらの記述です。
/** 数字以外を削除する */
$postno = preg_replace("/[^0-9]/", "", $postno);
Code language:PHP(php)
preg_replace()関数は、正規表現で置換します。
[^0-9] は数字以外という指定になります。
疑問:^って先頭から?否定?どっち?
正規表現で「^」は先頭から一致する場合という意味の記号になります。
なぜ[^0-9]が数字以外になるのでしょうか?
この辺の意味がよくわからずググって調べてみました。
すると、次のことがわかりました。
- 正規表現では^は先頭からという意味 ^0-9 であれば頭が0123456789と一致する場合真になります。
- []の中に^をつける場合「否定」という意味に変化します。[^0-9]であれば数字でない場合真となります。
疑問:結局 /[^0-9]/ ってどういう意味なの?
数字以外という意味は分かりましたが、/(スラッシュ)はどういう意味なんだろうと思いさらにググってみました。
すると、検索する場合に使われるということがわかりました。
つまり、数字以外([^0-9])を検索(/で囲う)して該当したものを置換するという意味になります。
疑問:入力された数字が7桁でない場合どうすればいいの?

郵便番号をフリー入力する場合、数字が7桁になるとは言い切れません。
数字が5桁や10桁など正しくない場合はどう対処すればよいのでしょうか?
答:数字の文字数を数えて7桁でない場合はエラーにします。

郵便番号は必ず数字7桁になります。
つまり7桁でなければエラーなのです。
ならば、数字が何文字あるか数え7桁でなければ、エラーであると判断できます。
そこでmb_strlen()関数を使用します。
この関数は指定した変数に何文字あるか数えてくれます。
使い方も以下のように変数を指定するだけです。
if (mb_strlen($postno) != 7)
{
/** エラーメッセージセット */
$sts["err"] = "郵便番号の桁数が正しくありません";
return $sts;
}
Code language:PHP(php)
7桁の数字にハイフンを入れる方法
1たん数字だけに変換してしまえば、あとは3桁目と4桁目の間にハイフンを入れれば統一フォーマットにできます。
サンプルでは以下の部分でこの処理を行っています。
/** 郵便番号のフォーマット変換 */
$postno_01 = substr($postno, 0, 3);
$postno_02 = substr($postno, -4, 4);
$sts["postno"] = "${postno_01}-${postno_02}";
Code language:PHP(php)
substr()関数は、指定した変数から文字を抽出してくれます。
substr($postno, 0, 3) であれば、$postnoの頭から3文字抽出します。
ではsubstr($postno, -4, 4)ってどう意味なのでしょう?
これは「後ろから数えて4文字目から4文字取り出す」という意味です。
substr($postno, 3, 4) でも同じことになりますが、このやり方であれば仮にハイフンが入っていても数字だけ取り出せます。
念には念をいれた作りが好みなので、マイナス指定のやり方で記述しています。
7桁の郵便番号にハイフンを足すという記事を書くつもりでしたが内容がちょっと濃くなりました
最初は数字7桁の郵便番号にハイフンを付け足すことについて記事を書くつもりでした。
そこでサンプルプログラムを組んでいたら、あれこれ例外処理が気になりました。
例外的な要素を何とかする方法を考えているうちに、思いのほか高性能な郵便番号入力フォームになっていました。
そこで、「変換可能な状態であれば可能な限りエラーにせず対応する」方向性で記事を書くことにいたしました。
思いもかけず良い経験をいたしました。
しかし、ここにきてさらに気になることが出てきました。
それは、次の事柄です。

例えば123-4567 という郵便番号は日本には存在しません。
書式は正しいですが、実在しない郵便番号はエラーにできないものか?
と思いました。
そこで実在しない郵便番号に対処する処理も組み込んでみました。
それについては次回解説いたします。
1週お待ちいただければ幸いです。
