正则表达式:'\ <'vs'\ b'

时间:2019-11-24 15:05:33

标签: regex linux bash

目前正在准备RHCSA和学习正则表达式。 '\ b'和'\ <'有什么区别?它们似乎几乎完全相同:在反斜杠之间匹配字符串。 (编辑) 示例:

[root@RHEL8DEV etc]# grep '\<root\>' * 2>/dev/null  | wc
    105     327    3658
[root@RHEL8DEV etc]# grep '\broot\b' * 2>/dev/null  | wc
    105     327    3658

即使在gnu.org上阅读后,我仍在挠头:

\ b 匹配空字符串,但仅在单词的开头或结尾处匹配。因此,“ \ bfoo \ b”将任何出现的“ foo”与单独的单词匹配。 “ \ bballs?\ b”与“ ball”或“ balls”作为单独的单词匹配。 不管缓冲区旁边显示什么文字,“ \ b”都会在缓冲区的开头或结尾匹配。

\ << / em> 匹配空字符串,但仅在单词开头。仅当后面有单词构成字符时,“ \ <”才会在缓冲区的开头匹配。 > 匹配空字符串,但仅在单词末尾匹配。仅当内容以单词组成的字符结尾时,“>”才会在缓冲区末尾匹配。

感谢您抽出宝贵的时间阅读此书。

2 个答案:

答案 0 :(得分:3)

只有您的grep特定版本的手册页才能显示它们是否完全相同。两者都不是完全可移植的。

传统上,在\<的某些版本中,\>仅在左单词边界处匹配,egrep在右边界处匹配。 (但是,例如Procmail使用了快捷方式,并且实际上对它们的定义完全相同。)

\b是Perl et al。中的一种较新的构造,方向是中立的,即,在单词序列的左侧或右侧的单词边界处为真文字字符。

答案 1 :(得分:0)

我个人发现\b\<\>得到更广泛的支持。我遇到的唯一例外是vim和BSD sed支持\<\>,而没有\b

关于它们的定义:在PCRE中,基本上是

这些链接指向Regex101对这些正则表达式的解释。请注意,该站点的四个受支持引擎都不了解\<\>应该做什么。

由于PCRE明确禁止非字母数字转义符的特殊含义,因此\<的意思是“直角尖括号”,因此(?:\<|\>)的意思是[<>]而不是\b。尽管标准扩展正则表达式也没有实现任何此类特殊含义(例如\<\>等项目都是非标准扩展名),但它们没有此显式禁止。

还要注意,在字符类中,情况有所不同。在大多数正则表达式解释器中,[\b]表示“文字退格字符”,并且等效于[\010][\x08](或\010\x08)。无论如何,将零宽度的项目放入字符类毫无意义。

使用GNU grep的差异示例,它接受两种格式:

$ echo yes |grep '\<yes'
yes
$ echo yes |grep '\byes'
yes
$ echo yes |grep '\>yes'
# (no output here means it failed)
$ 

在这里您可以看到方向性对\<\>很重要,而对\b则不重要


各种支持测试,仅用于命令行(截至2019/11/25的Debian Testing或FreeBSD 11.2,已注明):

$ echo y |grep '\<y'       # GNU grep w/ BRE, Basic Regular Expression
y
$ echo y |grep -E '\<y'    # GNU grep w/ ERE, Extended Regular Expression
y
$ echo y |grep -P '\<y'    # GNU grep w/ libpcre, Perl-Compatible Regular Expression
$ echo y |perl -ne 'print if /\<y/'  # perl proper
$ echo y |sed '/\<y/!d'    # GNU sed with BRE
y
$ echo y |sed -r '/\<y/!d' # GNU sed with ERE
y
$ echo y |sed '/\<y/!d'    # BSD sed with BRE (FreeBSD 11.2)
y
$ echo y |sed -E '/\<y/!d' # BSD sed with ERE (FreeBSD 11.2)
y
$ echo y |gawk '/\<y/'     # GNU awk
y
$ echo y |mawk '/\<y/'     # More POSIX-aligned
$ 

# python test (result printed as an array, in this case empty for no matches)
$ echo y |python -c 'import re,sys; print re.findall(r"\<y", sys.stdin.read())'
[]

grep -P(使用libpcre,并不总是编译成grep)不匹配,因为PCRE不能将\<识别为文字<字符。 / p>

$ echo y |grep '\by'       # GNU grep w/ BRE, Basic regex
y
$ echo y |grep -E '\by'    # GNU grep w/ ERE, Extended regex
y
$ echo y |grep -P '\by'    # GNU grep w/ libpcre, Perl-compatible regex
y
$ echo y |perl -ne 'print if /\by/'  # perl proper 
y
$ echo y |sed '/\by/!d'    # GNU sed with BRE
y
$ echo y |sed -r '/\by/!d' # GNU sed with ERE
y
$ echo y |sed '/\by/!d'    # BSD sed with BRE (FreeBSD 11.2)
$ echo y |sed -E '/\by/!d' # BSD sed with ERE (FreeBSD 11.2)
$ echo y |gawk '/\by/'     # GNU awk
$ echo y |mawk '/\by/'     # POSIX-ish awk
$ 

# python test
$ echo y |python -c 'import re,sys; print re.findall(r"\by", sys.stdin.read())'
['y']

请注意BSD sed如何接受\<但不接受\b,而GNU sed却同时接受两者。