如何转义未收集到特殊形状的特殊字符

时间:2017-06-13 07:49:29

标签: php regex preg-replace preg-match preg-quote

我有这个字符串:

$var = "Foo (.* ) bar blla (.* ) b*l?a$ bla bla ";

我想逃避*和?以及未收集到此形状的所有特殊字符

  

"&#34(*);

我想使用preg_quote($var, '\') 但它逃脱了所有特殊字符,我只需要转义单个特殊字符。 我想要这个结果:

$var = "Foo (.* ) bar bla(.*) b\*l\?a\$ bla bla ";

我想在preg_match中使用最终的$ var(结果),匹配另一个字符串中的所有(。*),以及我的案例中的特殊字符:

  

。,\,^,$,|,?,*,+,(,),[,],{,}和/

应该被解析为普通文本,因此应该对它们进行转义。虽然(。*)一个不应该被逃脱。 只有上面的特殊字符才能被转义,因为我必须在preg_match中使用$ var。其他特殊字符,无需逃避它们。

preg_match("/" . $var . "/s", $anotherstring, $match);

3 个答案:

答案 0 :(得分:2)

<强> EDIT3

好像它不适合你,所以这是另一次尝试。由于mickmack似乎对性能感到担心,他会很高兴它会下降到146步;)

替换

([\w\s]*(?:\([^)]*\)[\w\s]*)*)([*?$&])

$1\\$2

Here at regex101

它捕获可选范围的非特殊字符。它继续捕获可选的带括号的组,后跟可选的非特殊字符范围。最后一部分可以重复任意次。最后它捕获了特殊的角色。

所以我们必须捕获组 - 一组带有导致特殊字符的文本(如果有的话),另一组带有特殊字符。

用中间的\取代它们的内容,就可以了。

括号部分(happy mick ?;)也更灵活。它允许括号内更复杂的正则表达式(只是没有嵌套的括号)。

如果处理\的新要求不是必须的,而否定的单词类就行\W我们就会陷入炽热的76步 :) Here at regex101

- 原始回答 -

这是一种方法 - 替换

(?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))

\$1

注意!你必须逃脱php字符串中的\ - 即“\\ $ 1”。

由于php只允许使用look-behinds进行修复,因此它使用(?<!\(|\(.|\(..|\(...)构造在四个步骤中测试特殊字符之前没有开括号。然后它匹配并捕获特殊字符(不是字符,也不是空格)。最后,它使用负向前瞻以确保它后面没有右括号。在之前检查括号可能是多余的。

替换匹配的,捕获的角色本身 - $1 - 前面有想要的转义字符\就可以了。

See it here at regex101

修改

如果特殊字符仅限于您​​示例中的特殊字符,请使用

(?<!\(\.)([*?$&])(?!\))

作为搜索字符串并替换为\$1

匹配您的特殊字符,只要它们前面没有(.,后面跟)

Here at regex101

(这两种方式都没有防水,因为它们无法逃离 &中的(.& )。)

<强> EDIT2

由于OP将有问题的转义字符从/更改为\,因此已更新。 并删除了捕获组内的空间,因为OP不需要它。

答案 1 :(得分:1)

以下几种模式的表现优于ClasG的答案:

输入:Foo (.* ) bar blla (.* ) b*l?a$ && bla bla

模式:/\([^)]*\)(*SKIP)(*FAIL)|([^a-z\d ])/i替换为:\\\1

输出:Foo (.* ) bar blla (.* ) b\*l\?a\$ \&\& bla bla

Pattern Demo(仅 122 步骤)

基本上它只是省略了#34;受保护的&#34;括号部分并匹配任何非alphebetic&amp; amp;非空格字符。

如果你想专门列出这些符号,你可以将这个否定的字符类更改为OP中的字符类,如下所示:(仍 122 步骤)

/\([^)]*\)(*SKIP)(*FAIL)|([-\/~`!@#$%^&*()_+={}[\]|;:'"<>,.?\\])/

或者您只能使用示例中的符号,此处为完整模式(仍然 122 步骤):

/\([^)]*\)(*SKIP)(*FAIL)|([*?$&])/
  

所有ClasG的模式都比我上面的3种模式慢:

     

ClasG的书面模式:(?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))失败   并采取 418 步骤 - demo

     

ClasG的链接演示模式:(?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))是   正确但需要 367 步骤 - demo

     

ClasG的第三种模式:(?<!\(\.)([*?$&])(?!\))是正确的,但有一个   对括号部分的严格要求。这是最好的   该答案中的模式采取 186 步骤 - demo

答案 2 :(得分:-1)

使用preg_replace_callback,您可以查看正则表达式https://regex101.com/r/52qQwv/1

$s = 'Foo (.*) bar blla (.*) b*l?a$&& bla bla';
$regexp = '/([\.\*\?\&\$])[\w\s\&]/iu';
$f = function ($matches) {
    return '/' . $matches[1];
};
$a = preg_replace_callback($regexp, $f, $s);
var_dump($a);

string(39)“Foo(。)bar blla(。)b / * /?/ $ /&amp; bla bla”