【PHP8.x】preg_quote関数の使い方

作成日: 更新日:

preg_quote関数は、正規表現パターン中で特別な意味を持つ文字をエスケープする処理を実行する関数です。

主に、ユーザーからの入力など、動的に生成される文字列を正規表現のパターンの一部として安全に利用したい場合に役立ちます。正規表現には、.(任意の1文字)、*(直前の文字の0回以上の繰り返し)、+(直前の文字の1回以上の繰り返し)、?(直前の文字の0回または1回の繰り返し)、^(行頭)、$(行末)、[]{}()\|といった、特別な意味を持つ文字が存在します。これらの特殊文字を、正規表現の構文の一部としてではなく、単なる文字として検索したい場合、それらの文字の前にバックスラッシュ\を付けてエスケープする必要があります。

preg_quote関数は、指定された文字列の中から上記のような特殊文字を自動的に探し出し、それらの文字の前に\を追加することで、エスケープ処理を効率的に行います。例えば、「.test」という文字列を検索したい場合、そのまま正規表現パターンに組み込むと.が任意の文字として解釈されてしまいますが、preg_quote関数を通すことで「\.test」のように変換され、意図した通りの検索が可能になります。

さらに、正規表現パターンを囲むデリミタ文字(例えば/#など)がパターン内に含まれる場合もエスケープが必要となります。本関数の第二引数にそのデリミタ文字を指定することで、このデリミタ文字も同時にエスケープさせることができます。この関数を利用することで、意図しない正規表現の解釈を防ぎ、より安全で堅牢なコードを記述できるようになります。

基本的な使い方

構文(syntax)

<?php
// エスケープしたい文字列
$stringToEscape = "これは正規表現の特殊文字 . を含む文字列です。$や[]も含まれます。";

// オプションのデリミタ。正規表現のパターンでこの文字をデリミタとして使う場合に指定すると、
// $stringToEscape 内に含まれるこのデリミタ文字もエスケープされる。
// 例えば、正規表現のデリミタが '/' の場合:
$regexDelimiter = '/';

// preg_quote() 関数は、文字列内の正規表現の特殊文字をエスケープする。
// 第1引数: エスケープする文字列
// 第2引数: (オプション) 正規表現のデリミタ。この文字もエスケープされる。
$escapedString = preg_quote($stringToEscape, $regexDelimiter);

// $escapedString の例: "これは正規表現の特殊文字 \. を含む文字列です\。\$や\[\]も含まれます。"
// この結果は、正規表現パターンの一部として安全に利用できる。
?>

引数(parameters)

string $str, ?string $delimiter = null

  • string $str: クォート(エスケープ)する対象の文字列
  • ?string $delimiter = null: パターンで使用される区切り文字を指定します。指定された場合、その文字もエスケープされます

戻り値(return)

string

指定された文字列中の正規表現で特別な意味を持つ文字をエスケープした新しい文字列を返します。

サンプルコード

PHP preg_quoteで安全に正規表現を扱う

<?php

/**
 * preg_quote関数の基本的な使用方法を示すサンプルコード。
 *
 * この関数は、特定の文字列に含まれる正規表現の特殊文字をエスケープし、
 * その文字列をpreg_replaceなどの正規表現関数で安全にリテラルな検索パターンとして
 * 使用できるようにします。
 *
 * キーワード: php preg_replace double quotes
 * この例では、検索対象の文字列に正規表現の特殊文字とダブルクォートが含まれている場合でも、
 * preg_quoteがどのように機能するかを示します。
 */
function demonstratePregQuote(): void
{
    // 検索対象となる元のテキスト
    $text = "現在の価格は $5.00 (税別) です。特別な記号 *、+、?、[]、そして \"引用符\" も含まれます。";

    // ユーザー入力など、リテラルとして検索したい文字列。
    // 正規表現の特殊文字 ($ . * + ? [] () \) とダブルクォートを含む。
    $searchString = "$5.00 (税別) です。特別な記号 *、+、?、[]、そして \"引用符\" も含まれます。";

    // 検索文字列がマッチした場合に置換される文字列
    $replacementString = '【情報置換済み】';

    echo "--- 元のテキスト ---\n";
    echo $text . "\n\n";

    echo "--- 検索したい文字列 (リテラルとして扱いたい) ---\n";
    echo $searchString . "\n\n";

    // --- 1. preg_quoteを使用しない場合 (誤った動作やエラーの原因となる可能性) ---
    echo "--- preg_quote を使用しない場合 ---\n";
    try {
        // $searchString には正規表現の特殊文字が含まれているため、
        // そのまま正規表現パターンとして使用すると、意図しないマッチングが発生したり、
        // PHP 8 以降では無効なパターンとして `ValueError` を含むエラーが発生したりする可能性があります。
        // 例: $ は行末にマッチ、. は任意の一文字、*+? は繰り返し、[]() はグループ化や文字クラス。
        $patternWithoutQuote = $searchString;
        echo "正規表現パターン (未エスケープ): /" . $patternWithoutQuote . "/\n";

        // この行は、上記の理由によりエラーが発生する可能性が高いため、try-catchで囲んでいます。
        // PHP 8.0以降では、無効なPCREパターンはValueErrorをスローします。
        $resultWithoutQuote = preg_replace('/' . $patternWithoutQuote . '/', $replacementString, $text);

        echo "結果 (期待通りに動作しない可能性が高い、またはエラー):\n";
        echo $resultWithoutQuote . "\n\n";
    } catch (ValueError $e) {
        echo "エラーが発生しました: " . $e->getMessage() . "\n";
        echo "理由: 検索文字列に正規表現の特殊文字が含まれているため、パターンとして無効です。\n\n";
    } catch (Throwable $e) {
        echo "予期せぬエラーが発生しました: " . $e->getMessage() . "\n\n";
    }

    // --- 2. preg_quoteを使用する場合 (安全にリテラル検索を行う推奨される方法) ---
    echo "--- preg_quote を使用する場合 ---\n";

    // preg_quote を使用して $searchString 内の正規表現特殊文字をエスケープします。
    // 第二引数には、preg_replaceで使用する正規表現デリミタ(この例では '/')を指定します。
    // これにより、$searchString内にデリミタ文字が含まれていても安全にエスケープされます。
    //
    // 注意: ダブルクォート (") は正規表現の特殊文字ではないため、preg_quoteではエスケープされません。
    // しかし、文字列の一部として正しく扱われ、リテラルにマッチします。
    $quotedSearchString = preg_quote($searchString, '/');

    echo "preg_quoteでエスケープされたパターン:\n";
    echo $quotedSearchString . "\n\n";

    // エスケープされたパターンを使用して置換を行います。
    // これにより、$searchStringが完全にリテラルな文字列として扱われ、
    // 予期せぬ正規表現の挙動を防ぎ、安全かつ正確な置換が実現します。
    $resultWithQuote = preg_replace('/' . $quotedSearchString . '/', $replacementString, $text);

    echo "結果 (安全にリテラル検索を実行):\n";
    echo $resultWithQuote . "\n";
}

// 関数の実行
demonstratePregQuote();

?>

PHPのpreg_quote関数は、文字列に含まれる正規表現の特殊文字をエスケープし、その文字列をpreg_replaceなどの正規表現関数で安全にリテラルな検索パターンとして使用できるようにします。システムエンジニアが、ユーザー入力など意図しない正規表現の挙動を防ぎたい場合に非常に役立つ機能です。

この関数は、エスケープしたい元の文字列をstring $strとして受け取ります。オプションの?string $delimiter引数に、preg_replaceなどで使用する正規表現デリミタを指定すると、そのデリミタ文字もエスケープされます。これにより、デリミタ文字が検索文字列に含まれていても安全に扱えます。処理された結果は、特殊文字がエスケープされたstring型の文字列として返されます。

サンプルコードでは、$5.00 (税別) です。特別な記号 *、+、?、[]、そして "引用符" も含まれます。のような複雑な文字列をリテラルに検索し置換する例を示しています。preg_quoteを使用しない場合、$*といった正規表現特殊文字がパターンとして誤解釈され、PHP 8以降ではValueErrorが発生する可能性があります。一方、preg_quoteで事前にエスケープすることで、これらの特殊文字がただの文字として扱われ、preg_replace関数で意図したとおりに文字列全体を正確に検索し、安全に置換できるようになります。なお、キーワードにある「ダブルクォート(")」は正規表現の特殊文字ではないためpreg_quoteではエスケープされませんが、リテラルの一部として正しく認識され、問題なくマッチします。

preg_quoteは、正規表現の特殊文字をエスケープし、文字列をリテラルとして安全に扱うための関数です。これを使わずに正規表現特殊文字を含む文字列をパターンにすると、意図しない結果になったり、PHP 8以降ではValueErrorが発生したりする可能性があります。第二引数には、preg_replaceなどで使う正規表現デリミタを指定することで、デリミタ自体が検索文字列に含まれていても安全に処理できます。ダブルクォートは正規表現の特殊文字ではないためpreg_quoteではエスケープされませんが、リテラル文字列の一部として正しくマッチします。ユーザーからの入力など、動的な文字列を正規表現パターンとして利用する際は、必ずpreg_quoteでエスケープして安全性を確保してください。

preg_quoteで正規表現を安全にする

<?php

/**
 * preg_quote関数を使用して、動的な文字列を正規表現パターンとして安全にエスケープする例。
 * この関数は、ユーザーが提供する文字列を正規表現の検索パターンとして使用する際に、
 * 文字列に含まれる正規表現の特殊文字を適切にエスケープし、意図しないマッチを防ぎます。
 */
function demonstratePregQuoteUsage(): void
{
    // ユーザーが入力した、検索したい文字列を想定しています。
    // この文字列には、正規表現の特殊文字である '$' (行末) や '.' (任意の1文字) と、
    // キーワードにあるシングルクォート(')が含まれています。
    $userProvidedSearchTerm = "$20 or 'free' items.";

    // 検索語がマッチした場合に置換される文字列
    $replacementText = "discounted items";

    // 検索と置換の対象となる元の文章
    $originalText = "We offer great deals like $20 or 'free' items. Don't miss out!";

    // preg_quote を使用して、ユーザー提供の検索語を正規表現パターンとして安全にエスケープします。
    // - '$' と '.' は正規表現の特殊文字であるため、エスケープされます(例: \$20 or \'free\' items\.)。
    // - シングルクォート ('') は正規表現の特殊文字ではないため、エスケープされません。
    // - 第2引数でデリミタ '/' を指定することで、もし $userProvidedSearchTerm に '/' が含まれる場合もエスケープされます。
    $escapedPattern = '/' . preg_quote($userProvidedSearchTerm, '/') . '/';

    // preg_replace を使用して、エスケープされたパターンで文字列を置換します。
    // これにより、$userProvidedSearchTerm が正規表現ではなく、リテラル文字列として正確に検索されます。
    $modifiedText = preg_replace($escapedPattern, $replacementText, $originalText);

    echo "元の文章: " . $originalText . "\n";
    echo "ユーザーが提供した検索語: " . $userProvidedSearchTerm . "\n";
    echo "検索パターン (preg_quoteでエスケープ後): " . $escapedPattern . "\n";
    echo "置換後の文章: " . $modifiedText . "\n";
}

// 上記の関数を実行して、preg_quoteの動作を確認します。
demonstratePregQuoteUsage();

PHPのpreg_quote関数は、正規表現のパターンとして使用する文字列に含まれる特殊文字をエスケープするために利用されます。これにより、文字列を正規表現の特殊な意味ではなく、文字通りに(リテラルとして)安全に扱えるようになり、意図しないマッチングや予期せぬ挙動を防ぎます。

この関数は2つの引数を取ります。1つ目の$strはエスケープしたい元の文字列で、必須です。2つ目の$delimiterはオプションで、正規表現のデリミタ文字を指定します。このデリミタを指定すると、元の文字列内にデリミタ文字が含まれていても、それもエスケープの対象となります。関数は、特殊文字がエスケープされた新しい文字列を戻り値として返します。

サンプルコードでは、ユーザーが入力した"$20 or 'free' items."という文字列を、preg_replaceで安全に検索パターンとして利用する例を示しています。preg_quoteを通すことで、$.のような正規表現の特殊文字は自動的にバックスラッシュ\でエスケープされます(例: \$20 or 'free' items\.)。シングルクォート'は正規表現の特殊文字ではないため、エスケープされません。デリミタとして/を指定しているため、もし元の文字列に/が含まれていてもエスケープされます。これにより、動的な文字列を正規表現パターンとして使用する際のセキュリティと正確性が向上し、期待通りの検索と置換が可能となります。

preg_quote関数は、ユーザー入力などの動的な文字列を正規表現パターン内でリテラルとして安全に扱うために利用します。正規表現の特殊文字(例: $, .など)をエスケープすることで、意図しないマッチや誤作動を防ぎます。特にpreg_replaceなどと組み合わせる際は、preg_quoteの第二引数に、正規表現で使用するデリミタ(例: /)を必ず指定してください。これにより、検索文字列中にデリミタが含まれていても適切にエスケープされ、正規表現パターンが破損するのを防げます。キーワードにあるシングルクォート(')は正規表現の特殊文字ではないため、preg_quoteではエスケープされない点にご留意ください。

【PHP8.x】preg_quote関数の使い方 | いっしー@Webエンジニア