PHP PCRE正则表达式

时间:2014-06-11 20:28:46

标签: php regex latex non-greedy

在LaTeX中,表达式\o{a}{b}表示运算符'o'接受两个参数a和b。 LaTeX也接受\o{a},在这种情况下,将第二个参数视为空字符串。

现在我尝试将正则表达式\\\\o\{([\s\S]*?)\}\{([\s\S]*?)\}与字符串\o{a}\o{a}{b}匹配。它错误地将整个字符串作为匹配而不是。 (对这个字符串的正确解释是子字符串\o{a}{b}是唯一的匹配。)关键是我需要知道如何告诉PHP如果还有其他东西而不是{跟随第一个},那么它不是匹配。

我该怎么做?

修改:允许运算符的参数包含符号\{}。但在这种情况下,整个字符串不匹配的原因是因为a}\o{a中的大括号不符合LaTeX规则(例如{必须在}之前),所以{ {1}}不能是运算符的参数......

Edit2 :另一方面,a}\o{a应匹配,因为\o{{a}}{b}是有效参数。

3 个答案:

答案 0 :(得分:2)

我建议这样的事情:

$s = '\\o{a}\\o{a}{b}';
echo "$s\n";  # Check string
preg_match('~\\\o(\{(?>[^{}\\\]++|(?1)|\\\.)+\}){2}~', $s, $match);
print_r($match);

ideone demo

正则表达式:

  • 使用递归来处理嵌套大括号,
  • 也使用反斜杠([^{}\\\]\\\.)来避免使用语法大括号的字面括号。

\\\o             # Matches \o
(                # Recursive group to be
  \{             # Matches {
  (?>            # Begin atomic group (just a group that makes the regex faster)
     [^{}\\\]++  # Any characteres except braces and backslash
  |
     (?1)        # Or recurse the outer group
  |
     \\\.        # Or match an escaped character
  )+             # As many times as necessary
  \}             # Closing brace
){2}             # Repeat twice

当前正则表达式的问题在于,一旦此部分与\\\\o\{([\s\S]*?)匹配,它将尝试查找即将发生的下一个\},并且重要的是,您是否使用了懒惰量词或贪婪的。在真正的}进入正则表达式之前,您需要以某种方式阻止它与\}匹配。

这就是为什么你必须使用[^{}],因为你实际上可以在里面嵌套括号,这是使用递归的理想情况。

答案 1 :(得分:1)

要处理可能的嵌套花括号,需要使用递归功能:

$pattern = <<<'EOD'
~
\\o({(?>[^{}]+|(?-1))*}){2}
~x
EOD;

其中(?-1)是对最后一个捕获组的子模式的引用。

答案 2 :(得分:0)

我猜您需要考虑使用锚点^$

$pattern = '/^\\o\{.*\}(\{.*\})?$/';

我不知道您认为ab的值是什么值,因此您可以在此处用适当的类替换.*

这允许\0{a}\o{a}{b}格式。仅匹配\o{a}{b}修改:

$pattern = '/^\\o\{.*\}\{.*\}$/';

根据您的上一次修改,我建议将上面的.*替换为[^{]*,如其他答案中所述。