与Bash正则表达式匹配单词边界

时间:2014-12-15 01:53:27

标签: regex bash word-boundary

我想在bash中匹配以下表达式:

^.*(\b((720p)|(1080p)|(((br)|(hd)|(bd)|(web)|(dvd))rip)|((x|h)264)|(DVDscr)|(xvid)|(hdtv)|(ac3)|(s[0-9]{2}e[0-9]{2})|(avi)|(mp4)|(mkv)|(eztv)|(YIFY))\b).*$

我真想知道的是,测试字符串中的一个单词是否是此正则表达式中描述的单词之一(720p1080pbrrip,... )。而边界这个词似乎存在问题。

我使用的测试是[[ $name =~ $re ]] && echo "yes",其中$name是任意字符串,$re是我的正则表达式。

我错过了什么?

2 个答案:

答案 0 :(得分:4)

\b是PCRE扩展名;它在POSIX ERE(扩展正则表达式)中不可用,这是bash =~中的[[ ]]运算符将遵循的最小可能语法集。 (单个操作系统可能具有扩展此语法的libc;在这种情况下,这些扩展将在此类操作系统上可用,但在支持bash的所有平台上。)

作为基线,\b扩展实际上并没有非常强大的表达力 - 您可以编写任何使用它作为等效ERE的PCRE。但更好的是退后一步并质疑潜在的假设:当你说"字边界"时,你的意思是什么?如果您关心的是,如果以空格或字符串的开头或结尾开始和结束,那么您根本不需要\b运算符:

(^|[[:space:]])((720p)|(1080p)|(((br)|(hd)|(bd)|(web)|(dvd))rip)|((x|h)264)|(DVDscr)|(xvid)|(hdtv)|(ac3)|(s[0-9]{2}e[0-9]{2})|(avi)|(mp4)|(mkv)|(eztv)|(YIFY))($|[[:space:]])

请注意,我取出了最初的^.*并结束了.*$,因为这些结构在进行其他非锚定匹配时会自我否定; .*会使紧接其前面的^变得毫无意义,而.*恰好位于最后$之前。


现在,如果你想要一个完全等同于\b,当它紧接在一个序列开头的单词字符之前,那么我们会得到更像:

(^|[^a-zA-Z0-9_])

......同样,紧接在序列末尾的单词字符之后:

($|[^a-zA-Z0-9_])

这些都是有些堕落的情况 - 在其他情况下,模仿ERE中\b的行为可能会更复杂 - 但它们是您的问题似乎呈现的唯一情况。< / p>

请注意,\b的某些实现可以更好地支持非ASCII字符集,因此可以使用[^[:alnum:]_]而不是[^a-zA-Z0-9_]更好地进行描述,但它不是在这里明确定义了您来自或比较的实施。

答案 1 :(得分:1)

接受的答案错误可能在两个小问题上有误:

  • 据我所知,\b和&#39; \&lt; |&gt;&#39; (字边界匹配)不是PCRE的创新。再说一次,我无法在RE引擎中跟踪字边界匹配的介绍,所以它也可能是Perl。
  • 正如答案中正确陈述的那样,POSIX ERE不支持字边界匹配。但是,所有现代正则表达式引擎都提供字边界匹配作为基本RE的一部分,而不仅仅是ERE:您只需要找到语法。

也就是说,这个答案是非常具体Linux的{​​{1}}版本(最终Bash特定部分,其中可以也适用于所有BSD衍生物)。

  • 根据定义,GNU MacOSXRegular Expressions)支持RE\b作为字边界(\<|\>语法)。 它不是 Perl兼容的正则表达式扩展,AFAIK。 [1]

  • grep支持自Bash以来的GNU扩展REgrep -E语法)。 [2]

  • 因此,对于3.0的所有版本,Bash >= 3.0应该给我[[ " h " =~ '\bh\b' ]] && echo yes || echo no。它没有(见下一点)。

  • yes个版本Bash3.03.1会给我[[ " h " =~ '\bh\b' ]] && echo yes || echo no。请注意,模式本身是yes运算符的right hand sideRHS)参数。 [2]

  • =~更改了匹配运算符Bash-3.2的引用规则。 [2]

  • =~开始,理想情况下应将模式存储在变量中,并将变量作为Bash-3.2运算符提供给RHS运算符:=~ 。原因是引用规则发生了变化,因此如果模式在引号(pat='\bh\b' ; [[ " h " =~ $pat ]] && echo yes || echo no'')内提供,则模式将被解释为字符串而不是正则表达式。 [2]

最后,您的模式是正确的,它只是一个奇怪的引用问题:

""

此外,对于[samveen@ankhmorpork ~]# echo $BASH_VERSION 4.2.46(1)-release [samveen@ankhmorpork ~]# re='^.*(\b((720p)|(1080p)|(((br)|(hd)|(bd)|(web)|(dvd))rip)|((x|h)264)|(DVDscr)|(xvid)|(hdtv)|(ac3)|(s[0-9]{2}e[0-9]{2})|(avi)|(mp4)|(mkv)|(eztv)|(YIFY))\b).*$' [samveen@ankhmorpork ~]# for i in 720p 1080p brrip; do > [[ $i =~ $re ]] && echo yes for $i || echo no for $i > done yes for 720p yes for 1080p yes for brrip 上的Bash,边界匹配从MacOSX更改为\b(单词的开头)和'[[:<:]](单词结尾) [3]:

[[:>:]]

参考文献:

[1] GNU grep Manual: Regex section

[2] The Bash FAQ, by it's Author

[3] MacOSX manpage for re_format