やりたいこと
PHPで正規表現を用いて、住所から{都道府県}の部分を取り除き、{市区町村}以下を抽出したい。
具体的には、preg_replace()
関数を用いて、{都道府県}部分を空文字列''
に置換することで取り除く。
$address = '東京都港区芝公園4丁目2-8';
echo preg_replace(正規表現パターン, '', $address);
// 港区芝公園4丁目2-8
やったこと
正解にたどり着くまでの経緯を、ダメだったパターンを交えて記す。
(本記事では正規表現パターンの詳しい説明は割愛します)
ダメなパターン1
正規表現パターン:/.*(都|道|府|県)/
(任意の文字を0回以上 + 都・道・府・県のいずれか にマッチ)
$address = '東京都港区芝公園4丁目2-8';
echo preg_replace('/.*(都|道|府|県)/', '', $address);
// 港区芝公園4丁目2-8 (正しい!)
$address = '栃木県宇都宮市旭1丁目1-5';
echo preg_replace('/.*(都|道|府|県)/', '', $address);
// 宮市旭1丁目1-5 (おかしい!)
sample1では、東京都の部分がうまくマッチして置換できているが、
sample2では、宇都宮市の「都」までをパターンとしてしまい、「宮市旭1丁目1-5」となってしまっているので誤り。
ダメなパターン2
正規表現パターン:/^.{2,3}(都|道|府|県)/
(先頭に任意の文字が2~3回 + 都・道・府・県のいずれか にマッチ)
$address = '東京都港区芝公園4丁目2-8';
echo preg_replace('/^.{2,3}(都|道|府|県)/', '', $address);
// 東京都港区芝公園4丁目2-8 (おかしい!)
sample3では、東京都の部分が取り除かれると思いきや、元の文字列と同じ文字列が返されてしまった。
調べてみたところ、日本語はマルチバイト文字なので、{2,3}
の部分でバイト数がうまく機能していないことが判明した。
この場合、パターン修飾子「u」をつけて、対象文字列がUTF-8エンコードされていることを明示するか、
文字数指定の部分を3バイト換算({6,9}
)で書き換える必要がある。
$address1 = '東京都港区芝公園4丁目2-8';
echo preg_replace('/^.{2,3}(都|道|府|県)/u', '', $address1);
// 港区芝公園4丁目2-8 (正しい!)
echo preg_replace('/^.{6,9}(都|道|府|県)/', '', $address1);
// 港区芝公園4丁目2-8 (正しい!)
$address2 = '栃木県宇都宮市旭1丁目1-5';
echo preg_replace('/^.{2,3}(都|道|府|県)/u', '', $address2);
// 宇都宮市旭1丁目1-5 (正しい!)
echo preg_replace('/^.{6,9}(都|道|府|県)/', '', $address2);
// 宇都宮市旭1丁目1-5 (正しい!)
$address = '東京都府中市日吉町1−1';
echo preg_replace('/^.{2,3}(都|道|府|県)/u', '', $address);
// 中市日吉町1−1 (おかしい!)
sample4では、日本語のバイト数問題を解決して正しく置換できた。
しかし、sample5のような住所だと、「東京都」ではなく「東京都府」の部分までマッチしてしまっているので誤り。
成功パターン
上の2つの間違ったパターンを経て、以下のような結論に落ち着いた。
正規表現パターン:/(東京都|北海道|大阪府|京都府|^.{2,3}県)/u
(東京都 or 北海道 or 大阪府 or 京都府 or 先頭に任意の文字が2~3回 + 県にマッチ)
$address1 = '東京都港区芝公園4丁目2-8';
echo preg_replace('/(東京都|北海道|大阪府|京都府|^.{2,3}県)/u', '', $address1);
// 港区芝公園4丁目2-8 (正しい!)
$address2 = '栃木県宇都宮市旭1丁目1-5';
echo preg_replace('/(東京都|北海道|大阪府|京都府|^.{2,3}県)/u', '', $address2);
// 宇都宮市旭1丁目1-5 (正しい!)
$address3 = '東京都府中市日吉町1−1';
echo preg_replace('/(東京都|北海道|大阪府|京都府|^.{2,3}県)/u', '', $address3);
// 府中市日吉町1−1 (正しい!)
$address4 = '岐阜県山県市高木1000-1';
echo preg_replace('/(東京都|北海道|大阪府|京都府|^.{2,3}県)/u', '', $address4);
// 山県市高木1000-1 (正しい!)
東京都, 北海道, 大阪府, 京都府は完全一致でマッチさせ、
先頭にきた〇〇県または〇〇〇県をマッチさせることで、
正しく都道府県部分を取り除くことができた。
おわりに
正規表現は奥が深い......