3

この素晴らしい質問に対する上位投票の回答では、次の正規表現が(回答の関数からの)呼び出しで使用されています。preg_replaceauto_version

'{\\.([^./]+)$}'

この正規表現の最終目標は、指定されたファイル名からファイルの拡張子を抽出することです。ただし、この正規表現の最初の部分が機能する理由については混乱しています。すなわち:

正規表現\\.と同じように一致するのはなぜですか?\.

前者は(a)1つのリテラルバックスラッシュに一致し、その後に(b)任意の文字が一致し、2番目は1つのリテラルピリオドに一致するべきではありませんか?一重引用符で囲まれた文字列の規則\\は、文字通りの円記号を生成すると述べています。

この簡単な例を考えてみましょう。

$regex1 = '{\.([^./]+)$}';  // Variant 1 (one backslash)
$regex2 = '{\\.([^./]+)$}'; // Variant 2 (two backslashes)

$subject1 = '/css/foobar.css';   // Regular path
$subject2 = '/css/foobar\\.css'; // Literal backslash before period

echo "<pre>\n";
echo "Subject 1: $subject1\n";
echo "Subject 2: $subject2\n\n";

echo "Regex 1: $regex1\n";
echo "Regex 2: $regex2\n\n";

// Test Variant 1
echo preg_replace($regex1, "-test.\$1", $subject1) . "\n";
echo preg_replace($regex1, "-test.\$1", $subject2) . "\n\n";

// Test Variant 2
echo preg_replace($regex2, "-test.\$1", $subject1) . "\n";
echo preg_replace($regex2, "-test.\$1", $subject2) . "\n\n";
echo "</pre>\n";

出力は次のとおりです。

Subject 1: /css/foobar.css
Subject 2: /css/foobar\.css

Regex 1: {\.([^./]+)$}  <-- Output matches regex 2
Regex 2: {\.([^./]+)$}  <-- Output matches regex 1

/css/foobar-test.css
/css/foobar\-test.css

/css/foobar-test.css
/css/foobar\-test.css

簡単に言うと、呼び出しで同じ結果が得られるのはなぜですか?\\.preg_replace\.

4

2 に答える 2

11

二重のエスケープが行われていることを考慮してください。PHP\\.は「OK、これは本当に\.」と認識して言います。次に、正規表現エンジン\.は「OK、これは文字通りのドットを意味します」と認識して言います。

最初のバックスラッシュを削除すると、PHPは「これはバックスラッシュであり、その後にランダムな文字が続きます。仕様\.による一重引用符やバックスラッシュではないため、そのまま残ります」と表示します。正規表現エンジンは、上記と同じ結果を再度確認して提供します。\.\.

于 2013-01-23T16:09:26.713 に答える
0

ジョンによる完全に正しい答えへの追加:

さまざまな種類の引用符("vs ')の使用法を検討してください。使用する場合'、制御文字(改行など)を含めることはできません。これにより、さまざまなもの(、など)になる"可能性のある特別なキーの組み合わせを使用すること\?ができます。したがって、二重引用符で囲まれた文字列に実数を含める場合は、を使用して円記号をエスケープする必要があります。一重引用符を使用する場合、これは必要ないことに注意してください。?\n\t\\\

于 2013-01-23T16:18:49.387 に答える