PHPでの抽出方法

 正規表現パターンで一致した文字を抽出する方法です。PHPの、preg_match を使用していきます。preg_match 関数では正規表現パターンにマッチする文字が第3引数に配列という形で代入されます。関数の返り値自体は、パターンがあるかないかの診断となります。また、PCRE系では正規表現パターンを表現する場合、/(スラッシュ)でパターンを囲みます。

$str = '〒150-0021 東京都渋谷区';
$pattern = '/[0-9]{3}-[0-9]{4}/';

$match = array();

preg_match($pattern, $str, $match);
var_dump($match);


array (
  0 => '150-0021',
)
 パターン全体にマッチする文字が インデックス:0に格納されます。また、パターンの一部分を取り出したい場合などがあると思います。この場合、郵便番号の始め3桁と終わり4桁だとした場合、抽出パターンをパーレンで囲みます。こうすることでインデックスが新たに振られデータを格納するようになります。パーレンは抽出対象を明示する他に、正規表現パターンをグループ化する役割も兼ねているので、単純にグループ化だけを行いたい場合は、始まりのパーレン直後に ?: をつけて (?:パターン) のようにすると抽出対象になりません。
$str = '〒160-0000 東京都新宿区';
$pattern = '/([0-9]{3})-([0-9]{4})/';

$match = array();

preg_match($pattern, $str, $match);
var_dump($match);


array (
  0 => '160-0000',
  1 => '160',
  2 => '0000',
)
 次は、正規表現パターンに一致した文字を別の文字列に置き換える場合です。正規表現による文字列置換には、preg_replace関数を用います。郵便番号だと置き換える用途が浮かばないので、文中のURLをアンカータグ付きのURLに置き換えてみます。
$str = 'URL: http://www.yahoo.co.jp/ Yahoo! JAPAN';
$pattern = '/http:\/\/[0-9a-z_,.:;&=+*%$#!?@()~\'\/-]+/i';

$replace = '<a href="$0">$0</a>';
$replaced = preg_replace($pattern, $replace, $str);


var_dump($replaced);

<a href="http://www.yahoo.co.jp/">http://www.yahoo.co.jp/</a> Yahoo! JAPAN
 置き換え文字列($replace)で、$0 がパターンにマッチした文字(URL)に置き換わってるのがわかると思います。これは後方参照といって、マッチした文字を再び処理の中で用いるための仕組みです。$ と 数字の組み合わせにより、パターンにマッチした文字を参照できます。$0 は正規表現パターン全体にマッチする文字を表しています。もちろん $1、$2、$3 ... というのもあるわけですが、これはパターンの中で、パーレンに囲まれたパターンの文字を表します。

 尚、$ を使った後方参照はPHP固有の表現です。他の言語の正規表現で後方参照は \0 を用いています。PHPでも \0 という表記を用いることが出来ますので、上の例を $replace = '<a href="\0">\0</a>'; としても同じ結果が得られます。だだし \0 で困るのが後方参照のすぐ後に数字が続く場合です。1番目のカッコのパターンに '0' を付け加えた文字のつもりで '\10' と書いてしまうと10番目のカッコのパターンと判断されます。こんな場合は $ と大カッコを使って、'${1}0' と書いて、1番目のカッコのパターンに '0' を付け加えた文字を表します。特殊文字のパターンはバックスラッシュでエスケープしてあります。これは、正規表現として評価される前にPHP言語として評価されるための対策です。

TOP

正規表現パターン例

 良く使われる正規表現パターンを挙げてみます。ひとつの用途に対していくつものパターンが存在します。また長いパターンもあれば小さなパターンの組み合わせもあります。対象をどう的確に表現するかが肝になります。

・メールアドレス

/^[-._a-zA-Z0-9\/]+@[-._a-z0-9]+\.[a-z]{2,4}$/
 フォームに入力されたメアドのバリデーションパターンです。RFCで定義されてるメールアドレスの正規表現はとても長いですが、実用的な範囲はこれで足ります。ブランケットの外のドットはバックスラッシュでエスケープします。これにより特殊文字としての意味を省いています。また、ブランケット内の \/ は携帯電話用のメアド用です。他にも、
/^[-.\w\/]+@[-._[:lower:]\d]+\.[[:lower:]]{2,4}$/
などがあります。\w は単語を構成するもの(_0-9a-zA-Z)です。\d は数字(Digit)。[:lower:] は文字の集合を表すキャラクタクラスのひとつで a-z を表します。

・URL
/^(?:http|https):\/\/[\w,.:;&=+*%$#!?@()~\'\/-]+$/
 URLのバリデーションパターンでは、プロトコル先をふたつにマッチするようにしています。ftp もマッチしたい場合は、(?:http|https|ftp) などとします。 また、URLからプロトコル・ドメイン・リクエスト・クエリーを分けて抽出したい場合は以下のようにします。
/(http|https):\/\/([-._a-z\d]+\.[a-z]{2,4})([\w,.:;&=+*%$#!@()~\'\/-]*)\??([\w,.:;&=+*%$#!?@()~\'\/-]*)/

・電話番号
/^0\d{1,4}[-(]?\d{1,4}[-)]?\d{3,4}$/
 電話番号のバリデーションパターンでは、意外と難しいです。数字とハイフンだけという訳ではなく、固定、携帯、IP電話、フリーダイヤルと桁が異なるので注意が必要です。

・タグ
/<a href="([^"]+)">(.+?)<\/a>/is
 HTMLファイルからアンカータグのURLを抽出するパターンです。^" でダブルクオートを否定演算にかけています。つまり、ダブルクオートを区切りに間の文字を抽出するパターンとなります。また、(.+?) でリンク文字を引きぬいています。最後のパターン修飾子は i で大文字小文字の区別を無効、s でパターン中のドットを改行を含むという意味になります。
array (
  0 => 
  array (
    0 => '<a href="http://www.yahoo.co.jp/">Yahoo!JAPAN</a>',
    1 => 'http://www.yahoo.co.jp/',
    2 => 'Yahoo!JAPAN',
  ),
  1 => 
  array (
    0 => '<a href="https://www.google.co.jp/">Google</a>',
    1 => 'https://www.google.co.jp/',
    2 => 'Google',
  ),
  2 => 
  array (
    0 => '<a href="http://www.bing.com/?cc=jp">Bing</a>',
    1 => 'http://www.bing.com/?cc=jp',
    2 => 'Bing',
  ),
)

TOP

マルチバイト文字の正規表現パターン

 正規表現パターンにマルチバイト文字を扱う際は mb_ereg_** 関数を使うことになります。こちらは POSIX系の正規表現です。PCRE系とあきらかに違うところは、パターンを囲む "/" が無いところと、パターン修飾子を引数で指定するところです。その他は処理系ごとにも違うのでその都度確かめてください。マルチバイト文字を扱う際忘れてならないのが文字エンコーディングです。あらかじめ正規表現で扱う文字エンコーディングを mb_regex_encoding 関数で指定します。

・フリガナ

^[ ァ-ヶー]+$
 文字列が全角カタカナとスペースだけで構成されているパターン。

・ひらがな
^[ ぁ-んー]+$
 文字列が全角ひらがなとスペースだけで構成されているパターン。"ヴ"や"ヶ" は "ひらがな" にはありません。

・半角カナ
[。-゚]
 半角カナが含まれているかチェックするパターン。半角カナは濁点や半濁点も1文字なので、検索や並べ替え、文字列を部分的に取り出す場合など、プログラムを複雑にする要因となります。可能ならすべて"全角カナ"に統一を図る方が吉です。

 正規表現は結構負荷の高い処理です。乱発はパフォーマンス低下につながります。特定の文字が含まれるか判定するだけなら "strpos" や "strstr" で出来ますし、単純な文字列の置き換えなら "str_replace" や "strtr" で十分です。正規表現が本当に必要か、別の方法はないかよく検討してみましょう。

TOP