我有一个简单的字符串:
$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--
我想问一下:
(?:)
,即使(多个)(*SKIP)(*FAIL)
会在其中?我知道我一次要求更多问题,要求你多一点。请接受我的道歉!非常感谢你。
P.S:我已经使用以下PHP代码进行了测试:
$result = preg_replace_callback($patternX, function($matches) {
return rawurlencode($matches[0]);
}, $string);
echo $result;
答案 0 :(得分:1)
首先,两种模式都利用了SKIP-FAIL PCRE动词序列,这是一个众所周知的“技巧”,可以匹配某些文本,跳过它。有关更多详细信息,请参阅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)
,只需确保在|
之前使用它们以跳过相关匹配。
当您想要匹配特定上下文中的某些文本时,如果要在之后跳过/“避免”使用char,并且后面跟着某些字符,或者当您使用时,则使用SKIP-FAIL技术需要“避免”匹配整个序列的字符,就像在这种情况下一样,因此,SKIP-FAIL很好用。