PHP中的RegEx:匹配非转义引号之外的模式

时间:2009-05-19 17:59:55

标签: php regex

我正在编写一种方法来从SQL查询字符串中提取某些数据,并且只有在单引号的外部时才需要正则表达式匹配花括号内的任何单词。我还需要它来考虑转义(以反斜杠开头)引号的可能性,以及转义的反斜杠。

在以下示例中,我需要正则表达式匹配{FOO}而不是{BAR}:

blah blah {FOO} blah 'I\'m typing {BAR} here with an escaped backslash \\'
blah blah {FOO} 'Three backslashes {BAR} and an escaped quote \\\\\\\' here {BAR}'

我在PHP中使用preg_match来获取大括号中的单词(在本例中为“FOO”)。这是我到目前为止的正则表达式字符串:

$regex = '/' .
    // Match the word in braces
    '\{(\w+)\}' .
    // Only if it is followed by an even number of single-quotes
    '(?=(?:[^\']*\'[^\']*\')*[^\']*$)' .
    // The end
    '/';

我的逻辑是,因为我正在解析的唯一的东西是合法的SQL字符串(除了我添加的大括号之外),如果一组大括号后跟一个偶数的数字非转义引号,则必须在引号之外。

我提供的正则表达式100%成功除了考虑转义引号。我只需要确保在报价匹配之前没有奇数反斜杠,但对于我的生活,我似乎无法在RegEx中传达这一点。任何人?

3 个答案:

答案 0 :(得分:1)

处理转义引号和反斜杠的方法是以匹配对的方式使用它们。

(?=(?:(?:(?:[^\'\\]++|\\.)*+\'){2})*+(?:[^\'\\]++|\\.)*+$)

换句话说,当您扫描下一个引号时,您会跳过以反斜杠开头的任何一对字符。这将处理转义的报价和转义的反斜杠。这个预测将允许在引用部分之外的转义字符,这可能不是必需的,但它也可能不会受到伤害。

p.s。,注意占有式量词的自由使用(*+++);没有那些你可能会遇到性能问题,特别是如果目标字符串很大。此外,如果字符串可以包含换行符,您可能需要在DOTALL模式下进行匹配(也称为“单行”或“/ s”模式)。

但是,我同意mmyers:如果您正在尝试解析SQL,那么遇到正则表达式根本无法处理的问题。在正则表达式不好的所有事情中,SQL是最糟糕的事情之一。

答案 1 :(得分:0)

简单地,也许是天真的,str_replace你所有的双反斜杠。然后str_replace out转义单引号。此时,找到不在单引号之间的匹配(例如,使用现有的正则表达式)相对简单。

答案 2 :(得分:0)

如果你真的想为此使用正则表达式,我会分两步完成:

  1. 字符串非字符串分隔为preg_split

    $re = "('(?:[^\\\\']+|\\\\(\\\\\\\\)*.)*')";
    $parts = preg_split('/'.$re.'/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    
  2. 替换字符串中的任何内容

    foreach ($parts as $key => $val) {
        if (preg_match('/^'.$re.'$/', $val)) {
            $parts[$key] = preg_replace('/\{([^}]*)}/', '$1', $val);
        }
    }
    
  3. 但真正的解析器可能会更好,因为这种方法效率不高。