正则表达式替换匹配字符串的末尾两次

4

考虑以下程序:

#include <iostream>
#include <regex>

int main(int argc, char* argv[]) {
  if (argc==4)
    std::cout << std::regex_replace(
        argv[1], std::regex(argv[2]), argv[3]
      ) << std::endl;
}

运行中

./a.out a_a_a '[^_]+$' b

运行代码可以得到预期结果a_a_b。但是运行

./a.out a_a_a '[^_]*$' b

打印 a_a_bb

boost::regex_replace 的行为与此相同。

当我已经使用$时,我不理解为什么最后一个 a 后面的空字符串又被匹配了。


我认为这是因为 *。由于它匹配0或1,因此首先不匹配任何内容并放置一个 b,然后匹配该 b 并放置第二个 b。请确保您使用的是gcc 7.1.0或clang 3.0或更高版本。 - Shakiba Moshiri
1
这是许多正则表达式语法的已知行为。如果您想匹配某些内容,请确保您的模式不匹配空字符串。或者至少在开头和结尾都进行锚定。 - Wiktor Stribiżew
1
有人能解释一下这个设计的理由吗?如果在消耗$之后仍然有剩余内容需要匹配,我看不出它如何发挥作用。 - SU3
3个回答

1
这是 “*” 量词和 “+” 量词之间的简单差异。 “*” 匹配结束字母“a”,以及在结尾处的零宽度。您可以在此处查看它:[^_]*$。它不仅匹配最后一个“a”,而且还匹配其后面的零宽度,因此结果将是 “a_a_bb”。

为了确保以这种方式运作,请尝试:

[^_]*

如果您将程序输入a_a_a,输出将是:

bb_bb_bb

[^_]*


请注意,模式[^_]匹配所有三个a,但是一旦在该模式后面加上星号*,它会使该模式: 匹配单个a或空字符串(零宽度),因此模式[^_]*与主题a_a_a匹配6个点: a_之间以及其他。
a_a_a
^^^^^^

我的误解在于我认为 .* 匹配 nothing 时,nothing 必须出现在刚匹配的相同模式之后。这就是 sed 的行为方式。 - SU3
sed 's/[^_]*$/b/' <<< a_a_a 打印出 a_a_b - SU3
有很多正则表达式风格,而sed仅支持基本的,不够丰富和灵活。请查看我的回答,关于C++正则表达式库,以匹配当前行:https://stackoverflow.com/questions/46087665/std-regex-search-to-match-only-current-line/46098368#46098368 - Shakiba Moshiri

1
锚点不会被消耗(因为它们是0宽度的)。
您可以尝试制作模式abc$$$以匹配字符串abc,它仍将匹配,就像模式^^^abc一样。因此,您函数中的$没有被消耗,并允许a$(empty)$都匹配。

0

我认为是因为

+ means 1 or many (at least one occurrence for the match to succeed)
* means 0 or many (the match succeeds regardless of the presence of the search string)

所以,[^_]+$ 只匹配以非下划线结尾的字符串,而 [^_]*$ 匹配一个空字符和以非下划线结尾的字符串,因此它会匹配两个 b

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接