PHP PCRE 匹配标点符号但不匹配 ++
PHP PCRE match punctuation but not ++
我试了一段时间寻找这个问题的答案,但没找到。有许多与匹配文本相关的帖子,这些文本前面没有特定文本,但 none 似乎适用于 + 匹配的这种情况,但只有在前面有单个 + 时才允许(例如 ++)
我正在尝试从文本中删除标点符号,但保留两个连续的 ++ 符号,但让单个 + 符号消失
$text="Hello World! C+ C++ C#";
print_r(preg_replace('/(?!\+\+)[[:punct:]]/', ' ', $text));
结果(我不确定为什么后者 + 被删除?有人可以解释一下吗?):
Hello World C C+ C
如果我尝试:
$text="Hello World! C+ C++ C#";
print_r(preg_replace('/(?!\+)[[:punct:]]/', ' ', $text));
结果是:
Hello World C+ C++ C
但是我想要的结果是:
Hello World C C++ C
谢谢
更新:我意识到我可能应该提到我会有其他我想避免的角色。我可能把问题简单化了。例如,我可能想避免 # 也因此结果将是
Hello World C C++ C#
解决方案应该易于扩展。对于此信息缺失给您带来的不便,我们深表歉意。
您在这里有几个选择,一个是:
(?<!\+)[+#](?!\+)
# with lookarounds making sure no + is after/behind
在 PHP
:
<?php
$regex = '~(?<!\+)[+#](?!\+)~';
$string = 'Hello World! C+ C++ C#';
$string = preg_replace($regex, '', $string);
echo $string;
?>
另一种方法是使用 (*SKIP)(*FAIL)
机制(在本例中速度更快):
\+{2}(*SKIP)(*FAIL)|[+#]
# let two consecutive ++ always fail
在 regex101.com as well 上查看此演示。
最后但并非最不重要的:
如果你想添加也应该避免的 characters/expressions ,你可以将它们放在一个非捕获组中并让这个失败:
(?:\#|\+{2})(*SKIP)(*FAIL)|
[[:punct:]]
你的第一个正则表达式 (?!\+\+)[[:punct:]]
不起作用,因为它在否定中寻找两个连续的 +
符号 - 在每个位置 - 然后断言下一个直接字符是标点符号。当它看到 C++
,光标位于第一个 +
符号旁边时,此匹配成功,因为在第二个 +
之后没有 +
。所以先匹配+
.
Hello World! C+ C+|+ C#
^ Cursor here - (?!\+\+)[[:punct:]] is matched
正则表达式:
[[:punct:]]++((?<=\+)(?<=[^+]\+))
除了有条件的积极回顾断言之外,所有格匹配也可以完成这项工作。
解释:
[[:punct:]]++ // Match punctuation marks possessively - won't allow backtrack
((?<=\+) // Start of a conditional statement, check if last match is a `+`
(?<=[^+]\+) // If yes, it should not be preceded by another `+`
) // End of conditional
PHP:
preg_replace('@[[:punct:]]++((?<=\+)(?<=[^+]\+))@', ' ', $text)
更新
如果 +
字母前面总是有一些字母,则有一个更短的解决方案:
\b\+(?!\+)
第一个代码片段是这样工作的:找到一个标点符号,如果它不是 ++
序列的起点,则匹配并删除它。因此,C++
中的第二个 +
匹配,并被删除。
您可以使用 (*SKIP)(*FAIL)
动词匹配并 从匹配中丢弃 您想要保留的内容,只匹配您想要删除的内容:
preg_replace('/\+{2}(*SKIP)(*F)|[[:punct:]]+/', ' ', $text);
添加更多字符 - 以防万一:
preg_replace('/(?:[#^]|\*{3}|\+{2})(*SKIP)(*F)|[[:punct:]]+/', ' ', $text);
^^^ ^
详情:
\+{2}(*SKIP)(*FAIL)
- 匹配 2 个 +
符号,然后从匹配 中丢弃它们
|
- 或
[[:punct:]]+
- 匹配一个或多个标点符号。
在替换模式中,我们只是替换为space。
我认为这里有三种情况可以匹配加号。
必须匹配双加号才能越过它。
注意 - 这遵循从左到右的加号规则。除了这些没有规则。
查找:
[^\P{P}+]|(\+\+)\+|\+
替换:' '
已解释
[^\P{P}+] # Punctuation but not plus
|
( \+\+ ) # (1), Plus with leading ++
\+
|
\+ # Any old plus sign
可以减少到
[^\P{P}+] # Punctuation but not plus
|
( \+\+ )? # (1), Plus with optional leading ++
\+
我试了一段时间寻找这个问题的答案,但没找到。有许多与匹配文本相关的帖子,这些文本前面没有特定文本,但 none 似乎适用于 + 匹配的这种情况,但只有在前面有单个 + 时才允许(例如 ++)
我正在尝试从文本中删除标点符号,但保留两个连续的 ++ 符号,但让单个 + 符号消失
$text="Hello World! C+ C++ C#";
print_r(preg_replace('/(?!\+\+)[[:punct:]]/', ' ', $text));
结果(我不确定为什么后者 + 被删除?有人可以解释一下吗?):
Hello World C C+ C
如果我尝试:
$text="Hello World! C+ C++ C#";
print_r(preg_replace('/(?!\+)[[:punct:]]/', ' ', $text));
结果是:
Hello World C+ C++ C
但是我想要的结果是:
Hello World C C++ C
谢谢
更新:我意识到我可能应该提到我会有其他我想避免的角色。我可能把问题简单化了。例如,我可能想避免 # 也因此结果将是
Hello World C C++ C#
解决方案应该易于扩展。对于此信息缺失给您带来的不便,我们深表歉意。
您在这里有几个选择,一个是:
(?<!\+)[+#](?!\+)
# with lookarounds making sure no + is after/behind
在
PHP
:
<?php
$regex = '~(?<!\+)[+#](?!\+)~';
$string = 'Hello World! C+ C++ C#';
$string = preg_replace($regex, '', $string);
echo $string;
?>
另一种方法是使用
(*SKIP)(*FAIL)
机制(在本例中速度更快):
\+{2}(*SKIP)(*FAIL)|[+#]
# let two consecutive ++ always fail
在 regex101.com as well 上查看此演示。
最后但并非最不重要的: 如果你想添加也应该避免的 characters/expressions ,你可以将它们放在一个非捕获组中并让这个失败:
(?:\#|\+{2})(*SKIP)(*FAIL)|
[[:punct:]]
你的第一个正则表达式 (?!\+\+)[[:punct:]]
不起作用,因为它在否定中寻找两个连续的 +
符号 - 在每个位置 - 然后断言下一个直接字符是标点符号。当它看到 C++
,光标位于第一个 +
符号旁边时,此匹配成功,因为在第二个 +
之后没有 +
。所以先匹配+
.
Hello World! C+ C+|+ C#
^ Cursor here - (?!\+\+)[[:punct:]] is matched
正则表达式:
[[:punct:]]++((?<=\+)(?<=[^+]\+))
除了有条件的积极回顾断言之外,所有格匹配也可以完成这项工作。
解释:
[[:punct:]]++ // Match punctuation marks possessively - won't allow backtrack
((?<=\+) // Start of a conditional statement, check if last match is a `+`
(?<=[^+]\+) // If yes, it should not be preceded by another `+`
) // End of conditional
PHP:
preg_replace('@[[:punct:]]++((?<=\+)(?<=[^+]\+))@', ' ', $text)
更新
如果 +
字母前面总是有一些字母,则有一个更短的解决方案:
\b\+(?!\+)
第一个代码片段是这样工作的:找到一个标点符号,如果它不是 ++
序列的起点,则匹配并删除它。因此,C++
中的第二个 +
匹配,并被删除。
您可以使用 (*SKIP)(*FAIL)
动词匹配并 从匹配中丢弃 您想要保留的内容,只匹配您想要删除的内容:
preg_replace('/\+{2}(*SKIP)(*F)|[[:punct:]]+/', ' ', $text);
添加更多字符 - 以防万一:
preg_replace('/(?:[#^]|\*{3}|\+{2})(*SKIP)(*F)|[[:punct:]]+/', ' ', $text);
^^^ ^
详情:
\+{2}(*SKIP)(*FAIL)
- 匹配 2 个+
符号,然后从匹配 中丢弃它们
|
- 或[[:punct:]]+
- 匹配一个或多个标点符号。
在替换模式中,我们只是替换为space。
我认为这里有三种情况可以匹配加号。
必须匹配双加号才能越过它。
注意 - 这遵循从左到右的加号规则。除了这些没有规则。
查找:
[^\P{P}+]|(\+\+)\+|\+
替换:' '
已解释
[^\P{P}+] # Punctuation but not plus
|
( \+\+ ) # (1), Plus with leading ++
\+
|
\+ # Any old plus sign
可以减少到
[^\P{P}+] # Punctuation but not plus
|
( \+\+ )? # (1), Plus with optional leading ++
\+