如何使 perl 正则表达式不贪心?

How to make the perl regex not to be greedy?

我有这样的路径:

/nfs/usr/x86-64_linux71/gnua/4.0.0/features/com.asas.gnua.feature_4.0.0
/nfs/usr/x86-64_linux71/gnua/4.0.0/plugins/org.codehaus.jackson_1.0.0/META-INF
/nfs/usr/x86-64_linux71/gnua/4.0.0/configuration
/nfs/usr/x86-64_linux71/gnua/4.0.0/plugins/org.easymock_2.5.1
/nfs/usr/x86-64_linux71/gnua/4.0.0/features/org.eclipse.e4.rcp_1.6.100.v20180611-0422

我想构建一个正则表达式来捕获这些路径,因此 gnua 是第一组,4.0.0 是第二组。我试过了:

^\/nfs\/.*?\/.*?\_linux\d+\/(.*)?\/(.*)?\/.*?

但我得到 gnua/4.0.0 作为第一组,features 作为第二组。在 Perl 中如何使第一组为 gnua 而第二组为 4.0.0?也就是说,最后的.*?应该是features/com.asas.gnua.feature_4.0.0.

将问号移到匹配组中。

/^\/nfs\/.*?\/.*?\_linux\d+\/(.*?)\/(.*?)\/.*?/

更改定界符可提高可读性:

m{^/nfs/.*?/.*?_linux\d+/(.*?)/(.*?)/.*?}

但是使用 ([^/]*) 通常比 (.*?) 更安全。

正如 choroba 已经指出的那样,问号 应该移到捕获组括号内。

为了方便起见,您可以定义一个包含正则表达式的字符串(如果出现这种情况,它还允许在代码的其他部分重用它)。

#!/usr/bin/env perl
#
# vim: ai ts=4 sw=4

use strict;
use warnings;
use feature 'say';

my $re = '/nfs/usr/x86-64_linux.*?/(.*?)/(.*?)/';

while( <DATA> ) {
    my @arr = (,) if /$re/;
    say join("\t",@arr);
}

__DATA__
/nfs/usr/x86-64_linux71/gnua/4.0.0/features/com.asas.gnua.feature_4.0.0
/nfs/usr/x86-64_linux71/gnua/4.0.0/plugins/org.codehaus.jackson_1.0.0/META-INF
/nfs/usr/x86-64_linux71/gnua/4.0.0/configuration
/nfs/usr/x86-64_linux71/gnua/4.0.0/plugins/org.easymock_2.5.1
/nfs/usr/x86-64_linux71/gnua/4.0.0/features/org.eclipse.e4.rcp_1.6.100.v20180611-0422

输出

gnua    4.0.0
gnua    4.0.0
gnua    4.0.0
gnua    4.0.0
gnua    4.0.0