如何转义未聚集成特殊形状的特殊字符
How to escape special characters that that are not gathered in a special shape
我有这个字符串:
$var = "Foo (.* ) bar blla (.* ) b*l?a$ bla bla ";
我想转义 * 和 ?以及所有没有聚集在这个形状中的特殊字符
"(.*)"
我想用 preg_quote($var, '\')
但它转义了所有特殊字符,我只需要转义单个特殊字符。
我想要这个结果:
$var = "Foo (.* ) bar bla(.*) b\*l\?a$ bla bla ";
我想在 preg_match 中使用最终的 $var(结果)匹配其他字符串中的所有 (.*),以及在我的例子中的特殊字符 theses :
., \, ^, $, |, ?, *, +, (, ), [, ], {, }, and /
应该被解析为普通文本,因此它们应该被转义。而 (.*) 不应该被转义。
只有上面的特殊字符应该被转义,因为我将不得不在 preg_match 中使用 $var。其他特殊字符,不用转义。
preg_match("/" . $var . "/s", $anotherstring, $match);
编辑3
它似乎对你不起作用,所以这是另一种尝试。由于 mickmack 似乎担心性能,他会很高兴它减少到 146 步 ;)
替换
([\w\s]*(?:\([^)]*\)[\w\s]*)*)([*?$&])
与
\
它捕获非特殊字符的可选范围。它继续捕获一个可选的括号组,然后是一个可选的非特殊字符范围。最后一部分可以重复任意次数。最后它捕获了特殊字符。
因此我们必须捕获组 - 一个包含导致特殊字符(如果有)的文本,另一个 带有 特殊字符。
用中间的 \
替换它们的内容,就可以了。
括号部分也更灵活(快乐米克?;)。它允许在括号内使用更复杂的正则表达式(只是不是嵌套的括号)。
如果处理 \
的新要求不是必须的,并且否定词 class 没问题 \W
, 我们失败了达到惊人的 76 步 :) Here at regex101.
--原答案--
这是一种方法 - 替换
(?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))
与
$1
注意!您必须转义 php 字符串中的 \
- 即 "\\$1".
由于 php 只允许 fixed with look-behinds,它用 [=] 分四步测试 特殊字符 前没有左括号19=]构建。然后它匹配并捕获 特殊字符 (不是 单词字符 ,也不是 space)。最后,它使用否定的前瞻性来确保它后面没有跟一个右括号。不过,检查 和 之前的括号可能是多余的。
单独替换匹配和捕获的字符 - </code> - 前面加上想要的转义字符 <code>\
就可以了。
编辑
如果 特殊字符 仅限于您的示例中的字符,这是另一种方法 - 使用
(?<!\(\.)([*?$&])(?!\))
作为搜索字符串并替换为 $1
。
匹配您的特殊字符,只要它们前面没有(.
,后面也没有)
。
(这两种方法都不防水,因为它们无法逃离 (.& )
中的&
。)
编辑2
已更新,因为 OP 将有问题的转义字符从 /
更改为 \
。
并删除了捕获组中的 space,因为 OP 不需要它。
使用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);
字符串(39) "Foo (.) bar blla (.) b/*/?/$/&bla bla"
以下是一些优于 ClasG 答案的模式:
输入:Foo (.* ) bar blla (.* ) b*l?a$ && bla bla
模式:/\([^)]*\)(*SKIP)(*FAIL)|([^a-z\d ])/i
替换为:\
输出:Foo (.* ) bar blla (.* ) b\*l\?a$ \&\& bla bla
Pattern Demo(只需 122 步)
基本上它只是省略 "protected" 括号部分并匹配任何非字母和非 space 字符。
如果你想具体列出符号,你可以将OP中的否定字符class更改为字符class,如下所示:(仍然是122步)
/\([^)]*\)(*SKIP)(*FAIL)|([-\/~`!@#$%^&*()_+={}[\]|;:'"<>,.?\])/
或者您可以只使用示例中的符号,这是完整的模式(仍然是 122 个步骤):
/\([^)]*\)(*SKIP)(*FAIL)|([*?$&])/
All of ClasG's patterns are slower than my 3 patterns above:
ClasG's written pattern: (?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))
fails
and takes 418 steps - demo
ClasG's linked demo pattern: (?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))
is
correct but takes 367 steps - demo
ClasG's third pattern: (?<!\(\.)([*?$&])(?!\))
is correct but has a
strict requirement for the parenthetical portion. It is the best
pattern in that answer taking 186 steps - demo.
我有这个字符串:
$var = "Foo (.* ) bar blla (.* ) b*l?a$ bla bla ";
我想转义 * 和 ?以及所有没有聚集在这个形状中的特殊字符
"(.*)"
我想用 preg_quote($var, '\')
但它转义了所有特殊字符,我只需要转义单个特殊字符。
我想要这个结果:
$var = "Foo (.* ) bar bla(.*) b\*l\?a$ bla bla ";
我想在 preg_match 中使用最终的 $var(结果)匹配其他字符串中的所有 (.*),以及在我的例子中的特殊字符 theses :
., \, ^, $, |, ?, *, +, (, ), [, ], {, }, and /
应该被解析为普通文本,因此它们应该被转义。而 (.*) 不应该被转义。 只有上面的特殊字符应该被转义,因为我将不得不在 preg_match 中使用 $var。其他特殊字符,不用转义。
preg_match("/" . $var . "/s", $anotherstring, $match);
编辑3
它似乎对你不起作用,所以这是另一种尝试。由于 mickmack 似乎担心性能,他会很高兴它减少到 146 步 ;)
替换
([\w\s]*(?:\([^)]*\)[\w\s]*)*)([*?$&])
与
\
它捕获非特殊字符的可选范围。它继续捕获一个可选的括号组,然后是一个可选的非特殊字符范围。最后一部分可以重复任意次数。最后它捕获了特殊字符。
因此我们必须捕获组 - 一个包含导致特殊字符(如果有)的文本,另一个 带有 特殊字符。
用中间的 \
替换它们的内容,就可以了。
括号部分也更灵活(快乐米克?;)。它允许在括号内使用更复杂的正则表达式(只是不是嵌套的括号)。
如果处理 \
的新要求不是必须的,并且否定词 class 没问题 \W
, 我们失败了达到惊人的 76 步 :) Here at regex101.
--原答案--
这是一种方法 - 替换
(?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))
与
$1
注意!您必须转义 php 字符串中的 \
- 即 "\\$1".
由于 php 只允许 fixed with look-behinds,它用 [=] 分四步测试 特殊字符 前没有左括号19=]构建。然后它匹配并捕获 特殊字符 (不是 单词字符 ,也不是 space)。最后,它使用否定的前瞻性来确保它后面没有跟一个右括号。不过,检查 和 之前的括号可能是多余的。
单独替换匹配和捕获的字符 - </code> - 前面加上想要的转义字符 <code>\
就可以了。
编辑
如果 特殊字符 仅限于您的示例中的字符,这是另一种方法 - 使用
(?<!\(\.)([*?$&])(?!\))
作为搜索字符串并替换为 $1
。
匹配您的特殊字符,只要它们前面没有(.
,后面也没有)
。
(这两种方法都不防水,因为它们无法逃离 (.& )
中的&
。)
编辑2
已更新,因为 OP 将有问题的转义字符从 /
更改为 \
。
并删除了捕获组中的 space,因为 OP 不需要它。
使用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);
字符串(39) "Foo (.) bar blla (.) b/*/?/$/&bla bla"
以下是一些优于 ClasG 答案的模式:
输入:Foo (.* ) bar blla (.* ) b*l?a$ && bla bla
模式:/\([^)]*\)(*SKIP)(*FAIL)|([^a-z\d ])/i
替换为:\
输出:Foo (.* ) bar blla (.* ) b\*l\?a$ \&\& bla bla
Pattern Demo(只需 122 步)
基本上它只是省略 "protected" 括号部分并匹配任何非字母和非 space 字符。
如果你想具体列出符号,你可以将OP中的否定字符class更改为字符class,如下所示:(仍然是122步)
/\([^)]*\)(*SKIP)(*FAIL)|([-\/~`!@#$%^&*()_+={}[\]|;:'"<>,.?\])/
或者您可以只使用示例中的符号,这是完整的模式(仍然是 122 个步骤):
/\([^)]*\)(*SKIP)(*FAIL)|([*?$&])/
All of ClasG's patterns are slower than my 3 patterns above:
ClasG's written pattern:
(?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))
fails and takes 418 steps - demoClasG's linked demo pattern:
(?<!\(|\(.|\(..)([^\w\s])(?![^(]*\))
is correct but takes 367 steps - demoClasG's third pattern:
(?<!\(\.)([*?$&])(?!\))
is correct but has a strict requirement for the parenthetical portion. It is the best pattern in that answer taking 186 steps - demo.