grep regex中的非匹配组无法正常工作

时间:2017-02-27 14:51:54

标签: regex grep

我想从:

中提取1,10和100
  1 one -args 123
 10 ten -args 123
100 one hundred -args 123

然而,此正则表达式返回100

echo -e "  1 one\n 10 ten\n100 one hundred" | grep -Po '^(?=[ ]*)\d+(?=.*)'
100

不忽略前面的空格会返回数字(当然还有不需要的空格):

echo -e "  1 one\n 10 ten\n100 one hundred" | grep -Po '^[ ]*\d+(?=.*)'
  1
 10
100

我是否误解了grep / Perl中的非捕获正则表达式组(grep版本2.2,Perl作为-P标志应该使用其正则表达式)或者这是一个错误?我注意到release notes for 2.6 says "This release fixes an unexpectedly large number of flaws, from outright bugs (surprisingly many, considering this is "grep")"

如果有2.6的人可以尝试这些例子来确定这是一个错误(在2.2中)还是预期的行为。

3 个答案:

答案 0 :(得分:2)

问题在于什么被认为是匹配'通过grep。如果没有告诉grep部分总匹配不是你想要的,它会打印所有内容,直到匹配结束,无论匹配组如何。

假设:

$ echo "$txt"
  1 one -args 123
 10 ten -args 123
100 one hundred -args 123

你可以只获得第一列数字而不用多种方式引用空格。

使用GNU grep:

$ echo "$txt" | grep -Po '^[ ]*\K\d+' 
1
10
100

这里\K相当于断言后面的重复,将匹配的匹配文本重置为后来的内容。在\K之前的左手需要匹配,但不包含在由grep打印的匹配文本中。

Demo

AWK:

$ echo "$txt" | awk '/^[ ]*[0-9]+/{print $1}'

sed的:

$ echo "$txt" | sed 's/^[ ]*\([0-9]*\).*/\1/'

Perl:

$ echo "$txt" | perl -lne 'print $1 if /^[ ]*\K(\d+)/'

然后,如果您想在一行上匹配,请运行xargs

$ echo "$txt" | grep -Po '^[ ]*\K(\d+)' | xargs
1 10 100

或者,如果您使用的是awk或Perl,只需将其打印方式更改为不包含回车符。

答案 1 :(得分:1)

您可以通过以下方式删除不需要的空格:

echo -e "  1 one\n 10 ten\n100 one hundred" | grep -Po '^[ ]*(\d+)' | tr -d ' '

关于你为什么不工作的问题,它不是一个错误,它是按预期工作的,你只是误解了它应该如何工作。

如果我们关注这个^(?=[ ]*)\d+
(?=[ ]*)部分是一个先行断言。因此,这意味着正则表达式引擎会尝试检查^后面是否有零个或多个空格。但是断言本身不是匹配的一部分,所以实际上这个代码意味着:
  - 匹配后跟0或更多空格的^   - 在此^之后,匹配一个或多个数字

因此,只有当数字是该行的第一个字符时,您的代码才会匹配。前瞻不会帮助您处理用例。

答案 2 :(得分:0)

我认为这个锚点与前瞻混乱,这可能是一个后视,但它们不能模棱两可(我总是遇到那个)。所以以下方法可行:

echo -e "  1 one\n 10 ten\n100 one hundred" | grep -Po '(?=[ ]*)\d+(?=.*)'

至于更好的工具,我会使用awk,因为它适用于任何列驱动的数据。因此,如果您使用ps运行它,您可以执行以下操作:

ps | awk '/stuff you want to look for here/{print $1}'

awk默认会处理所有空格