PHP入門 | テキストと日付の操作 | 正規表現

テキストを扱うとき、避けて通れないものに「正規表現」がある。これは「パターン」と呼ばれる、テキストの並び方の規則のようなものを用意し、それに従ってテキストを探したり置換したりできる機能である。

通常の検索や置換では、決まったテキストしか探せない。たとえば「PHP」という単語を探す、といった方法である。それに対して正規表現では、「ある規則に沿って並んだテキストかどうか」を確認できる。たとえば「3桁の数字を検索する」や「aで始まりsで終わるテキストを探す」といったことができる。

正規表現のパターンは、「メタ文字」と呼ばれる特殊な記号を使って組み立てる。ここにはさまざまな記号と規則が用意されている。次の一覧にまとめておく。

基本的なメタ文字

記号 説明
\ 一般的なエスケープ文字
^ 検索対象、または複数行モードでの行の先頭
$ 検索対象、または複数行モードでの行の末尾
. 改行を除く任意の文字に一致
[] 文字クラス
| 選択肢の開始
() サブパターン
? 意味の拡張、0回または1回の繰り返し、または繰り返しの最小化
* 0回以上の繰り返し
+ 1回以上の繰り返し
{} 最小、最大の繰り返し指定

文字クラス内で使える特殊文字

メタ文字 説明
\ エスケープ文字
\b バックスペース
\f フォームフィード
\n 改行
\r キャリッジリターン
\t タブ文字
\d 数字1文字、[0-9]と同じ
\s 空白文字、空白、改行、キャリッジリターン、タブなど
\w 数字、英字、アンダースコア、[a-zA-Z0-9_]と同じ
^ 否定
- 範囲

このうち^-以外は、文字クラスの外でも使用できる。

文字クラス外で使う特殊文字

メタ文字 説明
\a アラート
\c 制御文字、後ろに文字を指定する
\e エスケープ
\D 数字以外の1文字、[^0-9]と同じ
\S 空白文字以外の任意の文字、[^\f\n\r\t\v]と同じ
\W 数字、英字、アンダースコア以外のすべて
\b 単語の境界
\B 単語境界以外
\A テキストの先頭
\Z テキストの終端または改行
\z テキストの終端
\ddd 8進数dddで表す文字
\xhh 16進数hhで表す文字

パターン修飾子

メタ文字 説明
i パターン中の文字を大文字、小文字を区別せずに一致させる
m 検索対象文字列を複数行として扱う
s .を改行を含む任意の文字に一致させる
x 空白文字を無視する
e preg_replace()の置換をPHPコードとして評価する
A 先頭でのみ一致
D $を最後でのみ一致させる
S より時間のかかる解析を行う
U 最短一致と最長一致の方式を反転する
X Perl非互換機能を利用する
u パターンをUTF-8として扱う

これらの文字はパターンの性質を規定するもので、パターンそのものには含まれない。

これを「すべて覚えなければならない」と言っているわけではない。実際に全部を覚えて使っている人は、それほど多くないだろう。よく使いそうな記号をいくつか覚えるだけでも、正規表現の便利さは実感できるはずである。

正規表現を使うための関数はいくつか用意されている。まずは「パターンマッチ」と「置換」の意味を覚えておくとよい。

パターンマッチ用の関数

$変数 = preg_match(パターン, テキスト, $変数);
$変数 = preg_match_all(パターン, テキスト, $変数);

第1引数のパターンを使って第2引数のテキストを調べ、パターンに一致した件数を返す。preg_matchは最初の一致だけを、preg_match_allはすべての一致を確認する。

興味深いのは、第3引数に用意する変数である。これは何か値を指定するものではない。パターン一致の結果をこの変数で受け取るためのものだ。多次元配列の形になっており、それぞれ一致したテキストの情報を集める。

また、第4引数としてパターンマッチに関する細かなフラグを指定することもできる。これは本格的に正規表現を使うようになってから調べるとよい。

置換用の関数

$変数 = preg_replace(パターン, 置換文字, テキスト);

正規表現を使って置換する関数である。第1引数にパターン、第2引数に置換文字、第3引数に調査対象のテキストを渡す。戻り値として、置換後のテキストが返される。

まずこの3つを知っていれば、いろいろなことができるようになる。パターンマッチではテキストデータの中から特定の要素を選び出せる。たとえばHTMLソースコードから<a>タグのリンクやメールアドレスだけを探すことができる。置換ができれば、通常の置換では絶対にできない複雑な置換処理も行えるようになる。

正規表現の使用例

それでは、正規表現を使う例を書いて実行してみよう。

<?php
    if ($_POST != null){
        $url = $_POST['text1'];
        $lines = file($url);
        $data = implode($lines);
        // パターンマッチ
        $pattern = "/([\w-]+)@([\w\.-]+)\b/";
        $flg = preg_match_all($pattern, $data, $matchs);
        if ($flg != false){
            $result = "";
            foreach($matchs[0] as $key => $val){
                $result .= $val . "\n";
            }
        } else {
            $result = "なし。";
        }
    }
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <form method="post" action="./index.php">
            <input type="text" name="text1" size="40" value="<?php echo htmlspecialchars($url); ?>"><br>
            <textarea name="area1" cols="30" rows="5"><?php echo $result; ?></textarea><br>
            <input type="submit">
        </form>
        <hr>
    </body>
</html>

ここではURLを入力すると、そのページのテキストを取得し、そこからメールアドレスだけを探して表示する。

上の入力フィールドにhttp://...のように調べたいページのURLを入力して送信してみよう。そのページに書かれているメールアドレスを探し、下のテキストエリアに表示する。

ここでは、まずfile関数を使ってURLのテキストを読み込み、それをimplodeで1つのテキストにまとめている。そして、パターンを使ってパターンマッチを実行している。

$pattern = "/([\w-]+)@([\w\.-]+)\b/";

これが用意したパターンである。ここで「正規表現は難しい、無理だ」とあきらめてしまう人も多いが、正直なところ、その必要はない。正規表現のパターンをインターネットで検索してみると、メールアドレスやURLなど、比較的よく使われるパターンを公開している人が多い。そうしたパターンをコピーして使えば、まず自分でパターンを作れなくても正規表現を利用できる。そして少しずつ自分で学んでいけば、後で役に立つことがあるだろう。

$flg = preg_match_all($pattern, $data, $matchs);

ここがパターンマッチを実行する部分である。この処理自体はそれほど難しいものではない。実行すると、$matchsという変数にパターン一致の結果が入る。

この変数はかなり複雑な構造になっている。一致したテキストを得るには、インデックスが0の値を取り出す。ここには連想配列が入っており、その値の部分に見つかったテキスト、つまりメールアドレスが保存されている。

まとめると、パターンマッチでは「結果配列のインデックス0にある連想配列から値を取り出す」ことで、見つかったすべてのテキストを得られる。これだけ覚えておけば、パターンマッチをある程度使えるはずである。

参考

さらに詳しく知りたい場合は、次のサイトを参考にしてほしい。