如何将正则表达式中的方括号与grep匹配?

时间:2015-05-05 04:18:52

标签: regex bash grep

我正在尝试将[]与grep匹配,但只能成功匹配[。无论我如何尝试,我都似乎无法匹配]

这是一个代码示例:

echo "fdsl[]" | grep -o "[ a-z]\+" #this prints fdsl
echo "fdsl[]" | grep -o "[ \[a-z]\+" #this prints fdsl[
echo "fdsl[]" | grep -o "[ \]a-z]\+" #this prints nothing
echo "fdsl[]" | grep -o "[ \[\]a-z]\+" #this prints nothing

编辑:我需要这样做的原始正则表达式就是这个:

echo "fdsl[]" | grep -o "[ \[\]\t\na-zA-Z\/:\.0-9_~\"'+,;*\=()$\!@#&?-]\+" 
#this prints nothing

N.B:我已经尝试了this帖子中的所有答案,但这并不适用于这个特殊情况。我需要在[]内使用这些括号。

3 个答案:

答案 0 :(得分:11)

根据POSIX正则表达式规范的BRE/ERE Bracketed Expression部分:

  
      
  1. [...]右括号(']')将失去其特殊含义,如果它首先出现在列表中(在最初的旋律之后('^'),则表示自己在括号表达式中,如果有的话)。否则,它将终止括号表达式,除非它出现在整理符号(例如"[.].]")中,或者是整理符号,等价类或字符类的结束右括号。特殊字符'.''*''[''\'(句点,星号,左括号和反斜杠)将在括号表达式中失去其特殊含义
  2.   

  
      
  1. [...]如果括号表达式同时指定'-'']'']'应首先放置('^'之后,如果有的话)和'-'最后在括号表达式中。
  2.   

因此,你的正则表达式应该是:

echo "fdsl[]" | grep -Eo "[][ a-z]+"

请注意E标志,该标志指定使用支持+量词的ERE。 BRE(默认模式)不支持+量词。

Mike Holt使用转义"[][a-z ]\+"回答+的解决方案有效,因为它在GNU grep上运行,extends the grammar to support \+ to mean repeat once or more。它实际上是undefined behavior according to POSIX standard(这意味着实现可以提供有意义的行为并记录它,或者抛出语法错误,或者其他)。

如果您认为您的代码只能在GNU环境中运行,那么使用Mike Holt的答案就完全没问题了。以sed为例,当您使用POSIX sed(没有标志切换到ERE)时,您会被BRE困住,并且使用POSIX BRE编写简单的正则表达式很麻烦,其中唯一定义的量词是*

原始正则表达式

请注意,grep逐行使用输入文件,然后检查该行是否与正则表达式匹配。因此,即使您在原始正则表达式中使用P标记,\n仍然是多余的,因为正则表达式不能跨行匹配。

虽然可以match horizontal tab without P flag,但我认为使用P标志执行此任务更为自然。

鉴于此输入:

$ echo -e "fds\tl[]kSAJD<>?,./:\";'{}|[]\\!@#$%^&*()_+-=~\`89"
fds     l[]kSAJD<>?,./:";'{}|[]\!@#$%^&*()_+-=~`89

问题中的原始正则表达式稍作修改(最后是unescape +):

$ echo -e "fds\tl[]kSAJD<>?,./:\";'{}|[]\\!@#$%^&*()_+-=~\`89" | grep -Po "[ \[\]\t\na-zA-Z\/:\.0-9_~\"'+,;*\=()$\!@#&?-]+"
fds     l[]kSAJD
?,./:";'
[]
!@#$
&*()_+-=~
89

虽然我们可以删除\n(因为它是多余的,如上所述),以及其他一些不必要的转义:

$ echo -e "fds\tl[]kSAJD<>?,./:\";'{}|[]\\!@#$%^&*()_+-=~\`89" | grep -Po "[ \[\]\ta-zA-Z/:.0-9_~\"'+,;*=()$\!@#&?-]+"
fds     l[]kSAJD
?,./:";'
[]
!@#$
&*()_+-=~
89

答案 1 :(得分:6)

一个问题是[是表达式中的特殊字符,并且无法使用\进行转义(至少不是我的grep风格)。解决方案是将其定义为[[]

答案 2 :(得分:3)

根据regular-expressions.info

在大多数正则表达式中,字符类中唯一的特殊字符或元字符是右括号(]),反斜杠(\),插入符号(^)和连字符( - )。通常的元字符是字符类中的普通字符,不需要用反斜杠转义。

......和......

结束括号(]),插入符号(^)和连字符( - )可以通过用反斜杠转义它们,或者将它们置于不具有其特殊含义的位置来包含。

因此,假设grep支持的正则表达式语法的特定风格符合这一点,那么我原本期望"[ a-z[\]]\+" 应该有效。

但是,我的grep版本(GNU grep 2.14)只匹配"[]"末尾的"fdsl[]"和此正则表达式。

但是,我尝试使用该引用中提到的其他技术(将]置于角色类中不能正常意义的位置,并且似乎有效:

$ echo "fdsl[]" | grep -o "[][a-z ]\+"
fdsl[]