36

只是出于好奇,我试图找出在 PHP 正则表达式模式中使用反斜杠的正确方法,如下所示:

测试 01:(3 个反斜杠)

$pattern = "/^[\\\]{1,}$/";
$string = '\\';

// ----- RETURNS A MATCH -----

测试 02:(4 个反斜杠)

$pattern = "/^[\\\\]{1,}$/";
$string = '\\';

// ----- ALSO RETURNS A MATCH -----

根据下面的文章,4 应该是正确的方法,但让我感到困惑的是两个测试都返回了一个匹配项。如果两者都是正确的,那么 4 是首选方式吗?

资源:

4

6 回答 6

54
// PHP 5.4.1

// Either three or four \ can be used to match a '\'.
echo preg_match( '/\\\/', '\\' );        // 1
echo preg_match( '/\\\\/', '\\' );       // 1

// Match two backslashes `\\`.
echo preg_match( '/\\\\\\/', '\\\\' );   // Warning: No ending delimiter '/' found
echo preg_match( '/\\\\\\\/', '\\\\' );  // 1
echo preg_match( '/\\\\\\\\/', '\\\\' ); // 1

// Match one backslash using a character class.
echo preg_match( '/[\\]/', '\\' );       // 0
echo preg_match( '/[\\\]/', '\\' );      // 1  
echo preg_match( '/[\\\\]/', '\\' );     // 1

当使用三个反斜杠匹配 a'\'时,下面的模式被解释为匹配 a'\'后跟一个's'

echo preg_match( '/\\\\s/', '\\ ' );    // 0  
echo preg_match( '/\\\\s/', '\\s' );    // 1  

当使用四个反斜杠匹配 a'\'时,下面的模式被解释为匹配 a'\'后跟一个空格字符。

echo preg_match( '/\\\\\s/', '\\ ' );   // 1
echo preg_match( '/\\\\\s/', '\\s' );   // 0

如果在字符类中也是如此。

echo preg_match( '/[\\\\s]/', ' ' );   // 0 
echo preg_match( '/[\\\\\s]/', ' ' );  // 1 

将字符串用双引号而不是单引号括起来不会影响上述结果。

结论:
无论是在括号字符类的内部还是外部,文字反斜杠都可以仅使用三个反斜杠匹配,'\\\'除非模式中的下一个字符也是反斜杠,在这种情况下,文字反斜杠必须使用四个反斜杠匹配。

建议:在寻求匹配反斜杠时,
始终在正则表达式模式中使用四个反斜杠。'\\\\'

转义序列

于 2013-03-12T18:59:21.353 回答
14

为避免这种不清楚的代码,您可以使用\x5c 像这样:)

echo preg_replace( '/\x5c\w+\.php$/i', '<b>${0}</b>', __FILE__ );
于 2014-07-30T19:33:22.787 回答
4

问题是,您使用的是字符类,[]因此无论嵌入多少文字反斜杠,它都将被视为单个反斜杠。

例如以下两个正则表达式:

/[a]/
/[aa]/

就正则表达式引擎而言,所有意图和目的都是相同的。字符类采用字符列表并“折叠”它们以匹配单个字符,按照“对于当前正在考虑的字符,它是否是列在[]? 中的任何字符”。如果您在课程中列出两个反斜杠,那么它将是“字符是黑斜杠还是反斜杠?”。

于 2012-06-15T03:16:31.163 回答
2

我几年前研究过这个。那是因为第一个反斜杠逃脱了第二个反斜杠,它们一起形成了模式中的“真正的反斜杠”字符,而这个真正的反斜杠逃脱了第三个反斜杠。所以它神奇地使 3 个反斜杠起作用。

但是,通常的建议是使用 4 个反斜杠而不是模棱两可的 3 个反斜杠。

如果我有任何错误,请随时纠正我。

于 2014-01-20T16:58:59.887 回答
1

答案https://stackoverflow.com/a/15369828/2311074非常具有说明性,但是如果您不知道 PHP 字符串中反斜杠的核心问题,您将根本无法理解。

PHP 字符串中反斜杠的核心问题在https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.single有解释,可能要注意最后两句:

指定字符串的最简单方法是将其括在单引号中(字符 ')。

要指定文字单引号,请使用反斜杠 () 对其进行转义。要指定文字反斜杠,请将其加倍 (\)。所有其他反斜杠实例将被视为文字反斜杠

所以简而言之,字符串中的两个反斜杠代表一个文字反斜杠。后面不跟 a 的单个反斜杠'也表示文字反斜杠。

这有点奇怪,但它意味着一个字符串'\\xxx'并且'\xxx'都代表同一个字符串\xxx
请注意,这'\\'xxx'是一个无效的字符串,而'\'xxx'代表字符串'xxx

我想它源于此:如果你想要一个文字单引号,你需要用反斜杠转义它。所以'hi\''代表字符串hi'。但是现在您最终会遇到您可能想要创建字符串hi\'hi\'不再起作用的情况(像这样没有结尾的无效字符串')。因此,需要一个额外的转义来防止特殊含义。\因此,一个确定的\转义\hi\可以写为 'hi\\'

这就是为什么与(都表示\\'\\\' )相同的原因,对于这两个字符串,你使用什么都无关紧要。'\\\\'

然而,它有一个令人惊讶的效果,如果你把琴弦加倍,它们就不一样了。这是因为用单引号括起来的 3 个反斜杠代表 2 个文字反斜杠。但是用单引号括起来的 6 个反斜杠仅代表 3 个文字反斜杠。而用单引号括起来的 4 个反斜杠表示 2 个文字反斜杠,而用单引号括起来的 8 个反斜杠表示 4 个文字(参见 MikeM 的示例)。因此,建议始终使用 4 而不是 3。

于 2021-12-05T23:38:36.840 回答
0

您还可以使用以下

$regexp = <<<EOR
schemaLocation\s*=\s*["'](.*?)["']
EOR;
preg_match_all("/".$regexp."/", $xml, $matches);
print_r($matches);

关键词:dochere,nowdoc

于 2017-05-16T17:18:55.303 回答