我使用的是Windows,但我想我的问题仍然正确地放在这里。
C:\Users\User>grep --version
GNU grep 2.6.3
C:\Users\User>sed --version
GNU sed version 4.2.1
我注意到以下工作(输出here
):
echo here | grep -E "\w+"
echo here | grep -E "[her]+"
但是,这不起作用(不输出任何内容):
echo here | grep -E "[\w]+"
这又会(输出here
):
echo here | grep -P "[\w]+"
我想这也是[\w]
Perl 正则表达式特有的东西。那是对的吗?
那么,我们来谈谈吧sed
。这有效(输出gone
):
echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"
再说一次,这不会(输出here
):
echo here | sed -r "s/[\w]+/gone/"
现在,我怎样才能激活 sed 的 Perl 正则表达式——有什么办法吗?
答案1
不同的工具及其版本支持正则表达式的不同变体。每个的文档都会告诉您它们支持什么。
标准的存在使得人们可以依赖所有符合标准的应用程序中可用的一组最小功能。
例如,所有现代实现sed
和grep
实现 POSIX 指定的基本正则表达式(至少有一个版本或另一个标准,但该标准在过去几十年里在这方面并没有太大发展)。
在 POSIX BRE 和 ERE 中,您有[:alnum:]
字符类。它与您的区域设置中的字母和数字相匹配(请注意,通常包含更多内容,a-zA-Z0-9
除非区域设置为 C)。
所以:
grep -x '[[:alnum:]_]\{1,\}'
匹配一个或多个alnums或_。
[\w]
POSIX 要求匹配反斜杠或w
.因此,您将找不到可用的grep
或sed
实现(除非通过非标准选项)。
POSIX 没有指定 alone 的行为\w
,因此允许实现做他们想做的事。 GNUgrep
很久以前就添加了这一点。
GNUgrep
曾经有自己的正则表达式引擎,但现在使用 GNU libc 的引擎(尽管它确实嵌入了自己的副本)。
它旨在匹配您所在区域中的数字和下划线。然而,它目前有一个错误,即它只匹配单字节字符(例如,在 UTF-8 语言环境中不匹配 é,尽管这显然是一个字母,而且它在所有 é 为单个字符的语言环境中确实匹配 é)特点)。
\w
perl regexp 和 PCRE 中还有一个正则表达式运算符。 PCRE/perl 不是 POSIX 正则表达式,它们完全是另一回事。
现在,随着 GNU 使用 PCRE 的方式grep -P
,它遇到了与不使用 PCRE 相同的问题-P
。不过,可以通过使用来解决这个问题(*UCP)
(尽管这在非 UTF8 语言环境中也有副作用)。
GNUsed
还使用 GNU libc 的正则表达式作为自己的正则表达式。它以这样的方式使用它,但它没有与 GNU 相同的错误grep
。
GNUsed
不支持 PCRE。代码中有一些证据表明以前曾尝试过,但它似乎不再提上议程。
如果你想要Perl的正则表达式,就使用perl
but。
sed
否则,我想说,与其尝试依赖/的特定实现的虚假非标准功能grep
,不如坚持使用标准并使用[_[:alnum:]]
。
答案2
你是对的 -\w
是 PCRE 的一部分 - perl 兼容正则表达式。但它不是“标准”正则表达式的一部分。http://www.regular-expressions.info/posix.html
某些版本sed
可能支持它,但我建议最简单的方法是通过指定标志perl
在模式下使用。 (随着)。 (更多详细信息参见sed
-p
-e
perlrun
)
但在该示例中您不需要[]
围绕它 - 这是针对有效内容组的。
echo here | perl -pe 's/\w+/gone/'
或者在 Windows 上:
C:\>echo here | perl -pe "s/\w+/gone/"
gone
C:\>echo here | perl -pe "s/[\w\/]+/gone/"
gone
看perlre
了解更多 PCRE 内容。
你可以在这里获取 perl: http://www.activestate.com/activeperl/downloads
答案3
我怀疑这一点,grep
并且sed
正在以不同的方式决定何时应用[]
和何时扩展\w
.在 Perl 中,正则表达式\w
表示任何单词字符,并[]
定义一个组以应用其中的任何字符作为匹配。如果您\w
在之前“展开”,[]
它将是所有单词字符的字符类。相反,如果您[]
首先这样做,您将拥有一个包含两个字符的字符类\
,w
因此它将匹配包含这两个字符中的一个或多个字符的任何模式。
因此,似乎sed
将[]
其视为包含要匹配的确切字符,而不是\w
像perl
and grep
do 那样尊重特殊序列。当然,[]
在这个例子中是完全没有必要的,但是人们也许可以想象它很重要的情况,但是你可以让它与括号和 ors 一起工作。