我有一个方法可以检查字符串是否包含特殊的unicode字符。我在这里找到了正则表达式http://w3.org/International/questions/qa-forms-utf-8.html。但我发现它不适用于超过307个字符的字符串。以下是示例代码:
$regex = '%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs';
$matches = null;
if (preg_match($regex,
'..........<p>
...............<a href="#tag"></a><br>
...............<a href="#tag"></a><br>
...............<a href="#tag"></a><br>
...............<a href="#tag"></a><br>
...............<a href="#tag"></a><br>
...............<a href="#tag"></a><br>
...............<a href="#tag"></a><br>
.........</p>', $matches)) {
echo 'IN';
} else {
echo 'OUT!';
}
我为测试添加了点而不是空格。当我运行这个脚本时,我得不到服务器的响应(尽管我已经设置了所有错误,但我甚至没有错误)。但是,如果我只从匹配的字符串中删除一个字符,它将按预期工作(IN被回显)。我似乎无法在网上找到任何可以帮助我的东西。调试没有用,因为它只是在if
停止(中断)(调试会话停止)。
以下是我在php.ini中的pcre设置:pcre.backtrack_limit:1000000,pcre.recursion_limit:100000
我已经尝试过在线工具检查正则表达式而且没有产生这个错误(它工作得很好)。
任何?感谢。
答案 0 :(得分:2)
原因似乎是服务器功能上限的bactracking限制(这就是您没有收到错误消息的原因)。
您可以使用以下方式限制回溯:
$regex = '%^(?>
[\x09\x0A\x0D\x20-\x7E]++ # ASCII
| (?>[\xC2-\xDF][\x80-\xBF])++ # non-overlong 2-byte
| (?>\xE0[\xA0-\xBF][\x80-\xBF])++ # excluding overlongs
| (?>[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2})++ # straight 3-byte
| (?>\xED[\x80-\x9F][\x80-\xBF])++ # excluding surrogates
| (?>\xF0[\x90-\xBF][\x80-\xBF]{2})++ # planes 1-3
| (?>[\xF1-\xF3][\x80-\xBF]{3})++ # planes 4-15
| (?>\xF4[\x80-\x8F][\x80-\xBF]{2})++ # plane 16
)*+$%xs';
关于回溯,原子组和占有量词:
回溯是一种机制,当子模式在字符串中的位置失败时,正则表达式引擎用于探索字符串中位置匹配的其他可能性。
让我们考虑字符串aaabcccb
和模式^.+cb$
:
string | pattern | state ------------+------------+-------------------------- aaabcccb | ^.+cb$ | BEGIN aaabcccb | ^.+cb$ | OK aaabcccb | ^.+cb$ | FAIL aaabcccb | ^.+cb$ | BACKTRACK aaabcccb | ^.+cb$ | FAIL aaabcccb | ^.+cb$ | BACKTRACK aaabcccb | ^.+cb$ | OK aaabcccb | ^.+cb$ | OK aaabcccb | ^.+cb$ | OK, SUCCEED ------------+------------+--------------------------
这描述了正则表达式引擎的默认行为,贪婪量词.+
的子模式采用了所有可能的(本例中的所有字符串),但在正则表达式引擎必须逐个字符后返回使子模式cb
成功。贪婪的量词允许这种行为,并可能让人物回来。
您可以使用占有量词来禁止回溯。 ^.++cb$
的示例:
string | pattern | state ------------+------------+-------------------------- aaabcccb | ^.++cb$ | BEGIN aaabcccb | ^.++cb$ | OK aaabcccb | ^.++cb$ | FAIL aaabcccb | ^.++cb$ | NO MATCH ------------+------------+--------------------------
正则表达式引擎无法在.++
匹配的子字符串中回溯,整个模式立即失败,因为找不到c
。
原子组定义了一个子模式,其中不允许正则表达式引擎回溯。换句话说,所有格量词和原子组是相同的特征:(?>a+)
&lt; =&gt; a++
注意:但是,请记住,只要未关闭,正则表达式引擎就可以在原子组内回溯:^(?>.+c)b$
将使用先前字符串成功,但^(?>.+)cb$
将失败。
一旦原子组被关闭,或者当你使用占有量词时,匹配的子串就是词源意义上的原子(即无法分割的东西)。但是,正则表达式引擎总是可以逐个原子地回溯,例如:^(?>ab)+abc$
(或abababc
)失败时,^(?>ab)++abc$
将匹配^(?>(?>ab)+)abc$
。
原子群和占有量词的主要优势之一(或禁止使用bactracking的事实)是减少使模式成功或失败的步骤数。
<强>改进:强>
由于占有量词和原子组在任何地方都使用,每个子串都是一劳永逸地匹配,当一个字符不在其中一个组中时,该模式将立即失败。
另一项改进是为交替的每个元素添加量词。字符串示例:zzzzzzzzzzzzza
使用模式:(?:a|b|c|...x|y|z)+
正则表达式引擎必须尝试交替的每个部分,直到它找到好的字母,并为每个字母(13x26 = 278个测试以获得所有z
)
使用模式:(?>a+|b+|c+|...x+|y+|z+)+
正则表达式引擎只需要26次测试,一旦到达z+
,它就会获得所有z
。