【问题标题】:Regular Expression: {n} and {n,m} ignore maximum number of repetition正则表达式:{n} 和 {n,m} 忽略最大重复次数
【发布时间】:2018-05-24 03:30:55
【问题描述】:

我对正则表达式的最大重复次数有疑问:{n} 和 {n, m}。

$ man grep
...
Repetition
    A regular expression may be followed by one of several repetition operators:
...
    {n}    The preceding item is matched exactly n times.
    {n,}   The preceding item is matched n or more times.
    {,m}   The preceding item is matched at most m times.  This is a GNU extension.
    {n,m}  The preceding item is matched at least n times, but not more than m times.
...

现在考虑一个测试文件:

$ cat ./sample.txt
1
12
123
1234

然后将其 grep 为恰好重复 2 次的 [0-9](数字):

$ grep "[0-9]\{2\}" ./sample.txt
12
123
1234

?为什么会包括 123 和 1234?

另外,我在相同的文本文件中查找重复至少 2 次但不超过 3 次的数字:

$ grep "[0-9]\{2,3\}" ./sample.txt
12
123
1234

???为什么返回“1234”?

一个明显的解决方法是使用 grep 和 reverse-grep 过滤掉过多的结果。例如,

$ grep "[0-9]\{2,\}" ./sample.txt | grep -v "[0-9]\{4,\}"
12
123

谁能帮我理解为什么 {n} 返回包含重复 n 次的模式的行?为什么 {n,m} 会返回重复 m 次的模式??

【问题讨论】:

  • 我认为所有 grep 所要做的就是在行中的某个地方找到它。它与额外的数字不匹配。

标签: regex grep


【解决方案1】:

除非您锚定正则表达式,否则它们可以匹配字符串中的任何位置。

$ grep "[0-9]\{2\}" ./sample.txt 将匹配任何包含 2 位数字的行。

使用^ 强制表达式从行首开始,使用$ 强制匹配到行尾。例如。

$ grep '^[0-9]\{2\}$' ./sample.txt
# Using single quotes to avoid potential substitution issues. Hat tip to @ghoti

这应该只返回12

【讨论】:

  • 事实上,如果$ 后面的文本可能被解释为替换,您只需要转义它。例如,尝试echo "$"。也就是说,切换到单引号可能是一个更好的主意。 :-)
  • 谢谢@ghoti / fish - 我正在使用 Fish shell,有点懒惰。 :)
  • 关于锚点的想法对我来说很有意义——谢谢。我会使用反向 grep 过滤掉结果,这样目标字符串就不需要出现在行的开头/结尾。
【解决方案2】:

模式可能出现在较长的文本中,也可能遵循相同的模式。对于 grep 使用 -o 选项来查看正则表达式在哪里找到了匹配项。两位数可以在一个由两位数组成的数字中找到,也可以在一个长度为 10 位的数字中找到。

另一个答案指向两个锚点,但有一个单词边界标记\b 匹配边界位置(如果使用)。这关闭了两端。不幸的是,POSIX BRE(grep 默认的正则表达式风格)不支持这一点,但在 GNU sed 中,您可以启用 Perl 正则表达式并对其进行测试:

grep -P '\b[0-9]{2}\b' file

单独使用grep 两个\<\> 匹配相同的位置:

grep '\<[0-9]\{2\}\>' file

【讨论】:

  • POSIX 也有单词边界。 [[:&lt;:]][0-9]\{2\}[[:&gt;:]]
  • @ghoti 是的,但无法让它与 grep 一起使用,因为我不确定我没有参考它。
  • 啊,有趣。在 macos 中为我工作,但在 FreeBSD 中没有。快捷方式,\&lt;\&gt; 在两者中都可以使用。我没有深入研究这个的意愿,所以我一会儿就删除我的 cmets。 :-)
  • @ghoti 让您的 cmets 在这里。也许其他人也会指出它。
猜你喜欢
  • 2012-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多