一个模式中有多个SKIP FAIL的PHP PCRE正则表达式



我有一个简单的字符串:

$string = '--#--%--%2B--';

我想对所有字符(包括"孤独"的%)进行百分比编码,除了-字符和形式为%xy的三元组。所以我写了以下模式替代方案:

$pattern1 = '/(?:[-]+|%[A-Fa-f0-9]{2})(*SKIP)(*FAIL)|./us';
$pattern2 = '/(?:[-]+)(*SKIP)(*FAIL)|(?:%[A-Fa-f0-9]{2})(*SKIP)(*FAIL)|./us';

请注意使用(多个)(*SKIP)(*FAIL)(?:)

匹配和替换的结果是相同的,也是正确的:

--%23--%25--%2B--

我想问:

  • 这两种模式等效吗?如果不是,哪一个应该是正确的url编码?你能简单解释一下为什么吗
  • 你会建议其他替代方案吗(暗示回溯控制动词),或者我的模式是个好选择吗
  • 即使(多个)(*SKIP)(*FAIL)在整个(选定的)模式中,我也可以只应用一个(?:)

我知道我一次问了更多的问题,对你的要求有点太高了。请接受我的道歉!非常感谢。


p.S:我已经用以下PHP代码进行了测试:

$result = preg_replace_callback($patternX, function($matches) {
return rawurlencode($matches[0]);
}, $string);
echo $result;

首先,这两种模式都利用了SKIP-FAIL PCRE动词序列,这是一个众所周知的"技巧"来匹配某些文本并跳过。请参阅(*SKIP)或(*F)如何处理regex?了解更多详细信息。

这两种模式产生相同的结果,(?:[-]+|%[A-Fa-f0-9]{2})(*SKIP)(*FAIL)匹配[-]+%[A-Fa-f0-9]{2},然后跳过匹配,(?:[-]+)(*SKIP)(*FAIL)|(?:%[A-Fa-f0-9]{2})(*SKIP)(*FAIL)首先尝试匹配[-]+,如果找到则跳过,然后尝试匹配%[A-Fa-f0-9]{2},如果找到,则跳过匹配。第二模式中的(?:...)非捕获组是冗余的,因为内部没有交替并且组没有被量化。您可以在模式中使用任意数量的(*SKIP)(*FAIL),只需确保在|之前使用它们即可跳过相关匹配。

当你想在特定的上下文中匹配一些文本时,当一个字符前面是后面是一些字符时,应该跳过/"避免"一个字符时,或者当你需要"避免"匹配整个字符序列时,比如在这种情况下,SKIP-FAIL技术是很好的使用方法。

最新更新