PCRE正则表达式无法描述什么?

时间:2016-02-17 06:54:56

标签: php regex pcre computation-theory

我正在使用大量的正则表达式,并且偶然发现了一个问题,即真正可以用正则表达式描述

我想到的第一个例子是匹配像XOOXXXOOOOXXXXX...这样的字符串。这将是由XO的交替序列组成的字符串,其中每个子部分仅由字符XO组成,比预先设置的要长另一个角色的序列。

有人可以解释正则表达式的正式限制吗?我知道这可能是一个相当学术性的问题,但我是一个好奇的人; - )

修改 由于我是一个php人员,我对PCRE标准所描述的正则表达式特别感兴趣,如下所述:http://php.net/manual/en/reference.pcre.pattern.syntax.php 我知道PCRE允许很多不属于原始正则表达式的东西,比如反向引用。

平衡括号的数学似乎是一般情况下正则表达式无法匹配的一个例子,但可以使用PCRE进行匹配(参见http://sandbox.onlinephpfunctions.com/code/fd12b580bb9ad7a19e226219d5146322a41c6e47实例):

$data = array('()', '(())', ')(', '(((()', '(((((((((())))))))))', '()()');    
$regex = '/^((?:[^()]|\((?1)\))*+)$/';

foreach($data as $d) {
  echo "$d matched by regex: " . (preg_match($regex, $d) ? 'yes' : 'no') . "\n";
}

3 个答案:

答案 0 :(得分:4)

  

我想到的第一个例子是匹配像XOOXXXOOOOXXXXX...这样的字符串。这将是由XO的交替序列组成的字符串,其中每个子部分仅由字符XO组成,比预先设置的要长另一个角色的序列。

是的,可以做到。

  1. 为了匹配非空的x序列,然后是更多的o,我们可以使用类似于平衡括号正则表达式的方法:

    (x(?1)?o)o+
    
  2. 为了匹配一个x和o的字符串,使得x的任何序列后跟一个更长的o序列(除了可选的最后一个),我们可以构建模式#1:

    ^o*(?:(x(?1)?o)o+)*x*$
    
  3. 当然,我们还需要一个带有x和o的模式#2的变体:

    ^x*(?:(o(?1)?x)x+)*o*$
    
  4. 要匹配满足上述两个条件的x和o的字符串,我们可以将模式#2转换为正向前瞻断言,并在模式#3中重新编号捕获组:

    ^(?=o*(?:(x(?1)?o)o+)*x*$)x*(?:(o(?2)?x)x+)*o*$
    
  5. 至于主要问题。 。 。我确信PCRE可以匹配任何无上下文的语言,因为支持 n 捕获组的(?n) 意味着你可以基本上为每个非终端创建一个子程序。例如,这种无上下文语法:

    • S aTb
    • S →ε
    • T cSd
    • T eTf

    可以写成:

    • 捕获组#1( S )→(a(?2)b|)
    • 捕获组#2( T )→(c(?1)d|e(?2)f)

    要将它组合成一个正则表达式,我们可以将它们全部连接起来,但是除了起始非终端之外,追加{0},然后添加^$:< / p>

    ^(a(?2)b|)(c(?1)d|e(?2)f){0}$
    

    但正如您从第一个示例中看到的那样,PCRE也可以匹配一些非上下文语言。 (另一个例子是 a n b n c n ,这是非上下文语言的典型示例。您可以通过组合PCRE将其与PCRE匹配EM>一 名词 b'/ EM> 名词 C < / em> m ,其中 m b < / em> n c n 使用前瞻性断言。虽然交集两种常规语言必然是常规语言,两种无上下文语言的交集必然是无上下文的;但是两个PCRE 定义的语言的交集可以定义通过PCRE。)

答案 1 :(得分:1)

正则表达式可以识别的所有语言的集合被称为“regular languages”。

下一个最复杂的语言是context-free languages。它们无法被任何正则表达式解析。标准的例子是“所有平衡的括号” - 所以“()()”和“(())”但不是“(()”。

无上下文语言的另一个好例子是HTML。

答案 2 :(得分:0)

我没有确切的证据表明,通过递归,平衡组,自引用组以及将文本附加到要测试的字符串中,这些都是不可能实现的。我很高兴能在所有这些或全部问题上被证明是错误的,因为我会学到一些东西!

1)数学非常糟糕。

例如,我认为使用PCRE来检测上升的数字序列是不可能的:也就是说,在“ 1 2 7 97 315 316 ...”上返回true。

2)我不确定是否有可能匹配从1连续增加的序列 ,例如“ 1 2 3 ...”,而没有详尽列出所有/1( 2( 3(...)?)?)?/之类的可能性直到您要检查的最大长度。

您可以通过在被测字符串中添加已知文本来使其正常工作(例如http://www.rexegg.com/regex-trick-line-numbers.html通过在文件末尾添加一系列数字来使其工作)。但是作为原始正则表达式,只有通过强制才能实现简单的数学运算。

3)我相信它将失败的另一个示例是“匹配总和为N的任何序列”。

因此对于N = 4,它应与43 11 32 21 1 1 12 1 1,{{ 1}},1 2 11 1 2,似乎您可以对其进行暴力破解,直到您意识到它也必须与1 1 1 1匹配为止。

4)以同样的方式,我认为您不能使用SI单位分析方程,并验证这些单位在方程的两边是否平衡。例如,“ 10N = 2kg * 5ms ^ -1”。不必介意检查值,只需检查单位是否正确即可。

5)然后,存在所有类别的问题,这些问题是目前计算机程序无法完成的,例如“检查字符串是否正确地用英语区分大小写”,这需要上下文相关的自然语言解析器来正确检测“时间像箭一样飞,但水果像香蕉一样飞”中“赞”的不同含义。