PHP:正则表达式忽略引号内的转义引号

时间:2011-04-17 17:48:08

标签: php regex

我在发布之前查看了相关问题,但我无法修改任何相关的答案以使用我的方法(不擅长正则表达式)。

基本上,这是我现有的行:

$code = preg_replace_callback( '/"(.*?)"/', array( &$this, '_getPHPString' ), $code );

$code = preg_replace_callback( "#'(.*?)'#", array( &$this, '_getPHPString' ), $code );

它们都匹配''""之间包含的字符串。我需要正则表达式来忽略它们之间包含的转义引号。因此,''之间的数据将忽略\'""之间的数据将忽略\"

非常感谢任何帮助。

6 个答案:

答案 0 :(得分:68)

对于大多数字符串,您需要允许转义任何(不仅仅是转义引号)。例如您最有可能需要允许转义字符,例如"\n""\t",当然还有转义转义:"\\"

这是一个经常被问到的问题,很久以前就已经解决了(并进行了优化)。 Jeffrey Friedl在他的经典着作中深入探讨了这个问题(作为一个例子):Mastering Regular Expressions (3rd Edition)。这是你正在寻找的正则表达式:

好:

"([^"\\]|\\.)*"
版本1:正常工作但效率不高。

更好:

"([^"\\]++|\\.)*""((?>[^"\\]+)|\\.)*"
版本2:如果您拥有所有权量词或原子组,则效率更高(参见:sin使用原子组方法的正确答案)。

最佳:

"[^"\\]*(?:\\.[^"\\]*)*"
版本3:更高效。实现Friedl的:“展开循环”技术。不需要占有或原子组(即这可以在Javascript和其他功能较少的正则表达式引擎中使用。)

以下是双语和单引号子字符串的PHP语法推荐的正则表达式:

$re_dq = '/"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"/s';
$re_sq = "/'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'/s";

答案 1 :(得分:10)

试试这样的正则表达式:

'/"(\\\\[\\\\"]|[^\\\\"])*"/'

(简短)解释:

"                 # match a `"`
(                 # open group 1
  \\\\[\\\\"]     #   match either `\\` or `\"`
  |               #   OR
  [^\\\\"]        #   match any char other than `\` and `"`
)*                # close group 1, and repeat it zero or more times
"                 # match a `"`

以下代码段:

<?php
$text = 'abc "string \\\\ \\" literal" def';
preg_match_all('/"(\\\\[\\\\"]|[^\\\\"])*"/', $text, $matches);
echo $text . "\n";
print_r($matches);
?>

产生

abc "string \\ \" literal" def
Array
(
    [0] => Array
        (
            [0] => "string \\ \" literal"
        )

    [1] => Array
        (
            [0] => l
        )

)
正如您在Ideone上看到的那样

答案 2 :(得分:1)

这有可能:

/"(?>(?:(?>[^"\\]+)|\\.)*)"/

/'(?>(?:(?>[^'\\]+)|\\.)*)'/

答案 3 :(得分:1)

这似乎与展开的循环一样快,基于一些粗略的基准,但更容易阅读和理解。它首先不需要任何回溯。

"[^"\\]*(\\.[^"\\]*)*"

答案 4 :(得分:0)

这会将引号留在

之外
(?<=['"])(.*?)(?=["'])

并使用global / g将匹配所有群组

答案 5 :(得分:0)

根据 W3 资源: https://www.w3.org/TR/2010/REC-xpath20-20101214/#doc-xpath-StringLiteral

一般的正则表达式是:

"(\\.|[^"])*"

(+捕获组第一次检查时不需要加反斜杠)

说明:

  • "..." 引号之间的任何匹配
  • (...)* 内部可以有从 0 到无穷大的任意长度
  • \\.|[^"] 首先接受任何后面有斜杠的字符 | (或)然后接受任何不是引号的字符

具有更好分组以便更好地处理任何引用的正则​​表达式的 PHP 版本可以是这样的:

<?php
    $str='"First \\" \n Second" then \'This \\\' That\'';
    echo $str."\n";
    // "First \" \n Second" then 'This \' That'

    $RX_inQuotes='/"((\\\\.|[^"])*)"/';
    preg_match_all($RX_inQuotes,$str,$r,PREG_SET_ORDER);
    echo $r[0][1]."\n";
    // First \" \n Second

    $RX_inAnyQuotes='/("((\\\\.|[^"])*)")|(\'((\\\\.|[^\'])*)\')/';
    preg_match_all($RX_inAnyQuotes,$str,$r,PREG_SET_ORDER);
    echo $r[0][2]." --- ".$r[1][5];
    // First \" \n Second --- This \' That
?>

试试看:http://sandbox.onlinephpfunctions.com/code/4328cc4dfc09183f7f1209c08ca5349bef9eb5b4

重要提示:在这个时代,对于不确定的内容,您必须在正则表达式的末尾使用u标志,例如/.../u以避免破坏{{1 }} 字符串如 multi-byte,或函数如 mb_ereg_match