【问题标题】:Right way to escape backslash [ \ ] in PHP regex?在 PHP 正则表达式中转义反斜杠 [ \ ] 的正确方法?
【发布时间】:2012-06-18 03:18:21
【问题描述】:

出于好奇,我试图找出正确的方法来转义反斜杠以用于 PHP 正则表达式模式,如下所示:

TEST 01:(3 个反斜杠)

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

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

测试 02:(4 个反斜杠)

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

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

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

资源:

【问题讨论】:

    标签: php regex


    【解决方案1】:
    // 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
    

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

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

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

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

    在字符类中也是如此。

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

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

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

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

    Escape sequences.

    【讨论】:

    • 当我尝试 [\] 时,我总是收到消息:preg_match(): Compilation failed: missing terminating ] for character class at offset 3
    • 你应该写[\\\\]
    【解决方案2】:

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

    echo preg_replace( '/\x5c\w+\.php$/i', '<b>${0}</b>', __FILE__ );
    

    【讨论】:

    • 我只想说非常感谢你。转义像 \n 这样的转义字符已经很痛苦了,但是在正则表达式中使用lookbehind 进行转义是一个挑战。
    • 避免back slash 只是用另外三个字符和一个反斜杠再次替换它自己。呸!
    • @CholthiPaulTtiopic 两个反斜杠不起作用,你应该写 4 个反斜杠。 onlinegdb.com/3IclPtzxW
    【解决方案3】:

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

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

    /[a]/
    /[aa]/
    

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

    【讨论】:

    • 所以在这两种情况下,正则表达式引擎都认为它是一个反斜杠?
    • \[\] 将是右括号的转义。 [\\] 将是字符类中的反斜杠。单个 char 类是毫无意义的,它与只有一个裸露的 `\\` 没有什么不同。
    • @MarcB 对于我来说,preg_replace('/[\\]/', '/', 'a\\b\\c.txt') 仍然会导致“编译失败”错误。
    • 这不是真的。你必须转义反斜杠
    【解决方案4】:

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

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

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

    【讨论】:

    • -1: and this true one escapes the 3rd one 不。仅执行一次通过。第三个反斜杠“转义”](这只会导致 ] 本身)。
    • @Lightness:那为什么'/(\\\r)\1+/'会匹配重复的'\'和'r'(我的意思是2个真正的字符)?你能解释一下吗?
    • \r 是一个转义序列; \] 不是。
    • 在 Python 中一样
    【解决方案5】:

    https://stackoverflow.com/a/15369828/2311074的答案很能说明问题,但是如果你不知道PHP字符串中反斜杠的核心问题你根本就看不懂。

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

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

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

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

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

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

    这就是为什么'\\\''\\\\' 相同(都代表\\)的原因,对于这两个字符串,你使用什么并不重要。

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

    【讨论】:

      【解决方案6】:

      你也可以使用下面的

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

      关键词:dochere, nowdoc

      【讨论】:

      • 很遗憾,这不会转义反斜杠,您仍然需要 \\\\ 来匹配搜索字符串中的 \
      • @Bjarke 为什么不\\\
      猜你喜欢
      • 1970-01-01
      • 2011-04-30
      • 2011-08-29
      • 2012-02-25
      • 2022-07-07
      • 1970-01-01
      相关资源
      最近更新 更多