【PHP】これで分かる関数! – 正規表現・サブパターンその2 –

PHP

更新履歴

更新日更新者更新内容
2021/8/21JJI・”はじめに”の段落を追加
・サンプルプログラムの実行結果に画面の画像を追加

はじめに

サンプルプログラムの中で次の記事で載せている関数を使用している場合があります。

後方参照

サブパターンでキャプチャした文字列は、同じパターン内で後から使用できます。
これを後方参照と呼びます。
\1はサブパターン内の最初にマッチした文字列、\2は2番目のサブパターンを表します。

文章だけだとわかりにくいので、サンプルプログラムを載せておきます。

サンプルプログラム

後方参照のサンプルプログラムです。

<?php
    // 引数の値への厳密な型付け
    declare(strict_types = 1);
    // 共通ライブラリの読み込み
    require_once __DIR__ . "../../../lib/sample_common.php";

    echo "ファイル名:" . basename(__FILE__) . "<br>\n";
    echo "【PHP】正規表現:サブパターン 後方参照<br>\n";

    // サブパターン1
    $str1 = "Tokyo is very very hot\n";
    // [[:alpha:]]+は1文字以上の英単語、/sは空白、\1は([[:alpha:]]+)\sでマッチした結果
    // 結果、英単語を繰り返す文字のため、very veryがマッチする
    $match = "/([[:alpha:]]+)\s\\1/";
    echo "検索対象文字列:" . $str1. ":<br>\n";
    echo "正規表現:" . $match . ":<br>\n";
    echo "正規表現の検索結果:" . preg_match($match, $str1, $hits) . ":<br>\n";
    echo "マッチした文字列の配列<br>\n";
    echo "0番目:マッチした文字列の全体、1番目以降は最初のサブパターンにマッチした部分<br>\n"; 
    echo_array1($hits);
?>

実行結果です。

・画面

・HTML

ファイル名:sample02_06_14.php<br>
【PHP】正規表現:サブパターン キャプチャしないグループ<br>
検索対象文字列:Tokyo is very very hot
:<br>
正規表現:/([[:alpha:]]+)\s\1/:<br>
正規表現の検索結果:1:<br>
マッチした文字列の配列<br>
0番目:マッチした文字列の全体、1番目以降は最初のサブパターンにマッチした部分<br>
[0]:very very: [1]:very:<br><br>

先読みと戻り読み

先読みと戻り読みは正規表現のパターンを処理する場合、「次の文字が○○の場合、これにマッチする」という機能です。
PHPマニュアルでは、先読みと戻り読みは条件付きサブパターンと呼ばれています。

この機能は例えば、文字列を分割する場合に使用することができます。
先読みを使用すると区切り文字の値にデータが続くかどうかを調べることができます。
戻り読みはその前のデータを調べます。

先読みと戻り読みに次のように肯定、否定の2種類があります。

書式意味
(?=subpattern)肯定先読み
(?!subpattern)否定先読み
(?<=subpattern)肯定戻り読み
(?<!subpattern)否定戻り読み

先読みと戻り読みまで使用できると正規表現を自由に使いこなすことができていると思います。
ただ、内容が分かりにくく、使用することはあまり多くないと思うのですぐに理解しなくても大丈夫です。

サンプルプログラム

先読みと戻り読みを使用したサンプルプログラムを載せておきます。

<?php
    // 引数の値への厳密な型付け
    declare(strict_types = 1);
    // 共通ライブラリの読み込み
    require_once __DIR__ . "../../../lib/sample_common.php";

    echo "ファイル名:" . basename(__FILE__) . "<br>\n";
    echo "【PHP】正規表現:サブパターン 先読みと戻り読み<br>\n";

    // 先読みなし、分割した文字は表示されない
    $str1 = "Mike,25,male,Tokyo\nRisa,20,female,Osaka\nMick,32,male,Aichi\n";
    // 文字列を","、または"\n"で分割する
    $match = "/(,|\n)/";
    echo "検索対象文字列:" . preg_replace("/\n/", "\\n", $str1). ":<br>\n";
    echo "正規表現:" . preg_replace("/\n/", "\\n", $match) . ":<br>\n";
    $hits = preg_split($match, $str1);

    echo_array1($hits);

    // 先読みあり、分割した文字は表示される
    $str1 = "Mike,25,male,Tokyo\nRisa,20,female,Osaka\nMick,32,male,Aichi\n";
    // 文字列を","、または"\n"で分割する
    $match = "/(?=,|\n)/";
    echo "検索対象文字列:" . preg_replace("/\n/", "\\n", $str1). ":<br>\n";
    echo "正規表現:" . preg_replace("/\n/", "\\n", $match) . ":<br>\n";
    $hits = preg_split($match, $str1);

    // コールバック関数
    // 改行コードを\nを\\nに変換し、表示できるようにする
    $call = function(string $str) :string {
        return preg_replace("/\n/", "\\n", $str);
    };

    echo_array1_call2($hits, $call);
?>

実行結果です。

・画面

・HTML

ファイル名:sample02_06_15.php<br>
【PHP】正規表現:サブパターン 先読みと戻り読み<br>
検索対象文字列:Mike,25,male,Tokyo\nRisa,20,female,Osaka\nMick,32,male,Aichi\n:<br>
正規表現:/(,|\n)/:<br>
[0]:Mike: [1]:25: [2]:male: [3]:Tokyo: [4]:Risa: [5]:20: [6]:female: [7]:Osaka: [8]:Mick: [9]:32: [10]:male: [11]:Aichi: [12]::<br><br>
検索対象文字列:Mike,25,male,Tokyo\nRisa,20,female,Osaka\nMick,32,male,Aichi\n:<br>
正規表現:/(?=,|\n)/:<br>
[0]:Mike:[1]:,25:[2]:,male:[3]:,Tokyo:[4]:\nRisa:[5]:,20:[6]:,female:[7]:,Osaka:[8]:\nMick:[9]:,32:[10]:,male:[11]:,Aichi:[12]:\n:<br>

参考

先読みと戻り読みは次のPHPマニュアルに詳しく解説しています。
さらに詳細なことを知りたい方を見てください。

PHP: 条件付きサブパターン - Manual

コメント