不管是否 Perl,有时正则表达式的问题在于它的贪心。假设我想捕获某人的名字,字符串如下所示:
Bob Baker
我可以使用这个正则表达式:
sed 's/^\(.*)\ .*$/\1/'
这适用于Bob Baker,但不适用于Bob Barry Baker。问题是我的正则表达式是贪婪的并且会选择所有字符直到最后一个空格,所以我最终不会Bob
使用Bob Baker
. 解决此问题的一种常用方法是指定除您不想要的字符之外的所有字符:
sed 's/^\([^ ]*)\ .*$/\1/'
在这种情况下,我指定了任何不包括空格的字符集。这将同时改变Bob Baker
和Bob Rudolph Baker
为 just Bob
。
Perl 有另一种指定非贪婪正则表达式的方法。在 Perl 中,您?
向您的子表达式添加一个您希望不贪婪的子表达式。在上面的示例中,这两个都会将包含的字符串更改Bob Barry Baker
为Bob
:
$string =~ s/^([^ ]+) .*$/$1/;
$string =~ s/^(.+?) .*$/$1/;
顺便说一句,这些是不等价的!
除了空格正则表达式之外,我可以这样做:
$string =~ /^([^ ]+)( )(\[\d{4}\])( )(\(\d+p\))(\.)([^.]+)/
使用非贪婪限定符:
$string =~ /^(.+?)( )(\[\d{4}\])( )(\(\d+p\))(\.)(.*)/
并且,使用x
限定符允许您将相同的正则表达式放在多行上,这很好,因为您可以添加注释来帮助解释您在做什么:
$string =~ /
^(.+?) #Any set of characters (non-greedy)
([ ]) #Space
(\[\d{4}\]) #[1959]
([ ]) #Space
(\([0-9]+p\)) #(430p)
[.] #Period
([^\.]+) #File Suffix (no period)
/x
而且,此时,您不妨遵循 Damian Conway关于 Perl 正则表达式的最佳实践建议。
$string =~ /
\A #Start of Regular Expression Anchor
( .+? ) #Any set of characters (non-greedy)
( [ ] ) #Space
( \[ \d{4} \] ) #[1959]
( [ ] ) #Space
( \( [0-9] +p \) ) #(430p)
( [.] ) #Period
( [^\.]+ ) #File Suffix (no period)
\Z #End of string anchor
/xm;
由于x
忽略所有空白,我什至可以在同一行的子组之间添加空格。在这种情况下,( .*+? )
只是比(.*+?)
. 是否( \( [0-9] +p \) )
或( \( [0-9]+p \) )
什( \([0-9]+p\) )
至更容易理解取决于您。
而且,是的,答案看起来很像思南的答案。
顺便说一句,正如 Sinan 所示,使用非贪婪正则表达式限定符能够解析a b c d e [1234] (1080p).mov
,而使用不包含空格子表达式的所有内容则不能。这就是为什么我说它们不一样。