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

PHP PCRE regex with multiple SKIP FAIL in a pattern

我有一个简单的字符串:

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

我想对所有字符(包括 "lonely" %)进行百分号编码,- 字符和 %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--

我想问:

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


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

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

首先,这两种模式都利用众所周知的 SKIP-FAIL PCRE 动词序列 "trick" 来匹配一些文本,然后 跳过 它。有关详细信息,请参阅 How do (*SKIP) or (*F) work on 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 技术用于当你想在特定上下文中匹配某些文本时,当一个字符应该被跳过时/"avoided" 如果它在前面 后面一些字符,或者当你需要 "avoid" 匹配整个字符序列时,就像在这种情况下,因此,SKIP-FAIL 很好用。