在Perl中匹配替换数字

时间:2013-07-23 11:39:35

标签: regex perl substitution

我有这个小脚本:

my @list = ('R3_05_foo.txt','T3_12_foo_bar.txt','01.txt');

foreach (@list) {
    s/(\d{2}).*\.txt$/$1.txt/;
    s/^0+//;
    print $_ . "\n";
}

预期输出为

5.txt
12.txt
1.txt

但相反,我得到了

R3_05.txt
T3_12.txt
1.txt

最后一个很好,但我无法理解为什么正则表达式为我提供了$1的字符串开头。

4 个答案:

答案 0 :(得分:3)

尝试这种模式

foreach (@list) {
    s/^.*?_?(?|0(\d)|(\d{2})).*\.txt$/$1.txt/;
    print $_ . "\n";
}


说明:

我在这里使用分支重置功能(即(?|...()...|...()...)),它允许将多个捕获组放在一个引用中($1这里)。因此,您可以避免使用第二个替换来从捕获的左侧修剪零。

要从号码前的开头删除所有内容,我使用:

.*?     # all characters zero or more times 
        # ( ? -> make the * quantifier lazy to match as less as possible)
_?      # an optional underscore



请注意,您可以确保只有2位数字添加前瞻,以检查后面是否有数字:

s/^.*?_?(?|0(\d)|(\d{2}))(?!\d).*\.txt$/$1.txt/;

(?!\d)表示后面没有数字

答案 1 :(得分:2)

这里的问题是你的替换正则表达式没有涵盖整个字符串,所以只有部分字符串被替换。但是,您正在使用一个相当复杂的解决方案来解决一个简单

似乎您想要的是从字符串中读取两位数字,然后将.txt添加到其末尾。那么为什么不这样做呢?

my @list = ('R3_05_foo.txt','T3_12_foo_bar.txt','01.txt');

for (@list) {
    if (/(\d{2})/) {
        $_ = "$1.txt";
    }
}

要克服前导零效果,您可以通过向其添加零来强制转换为数字:

$_ = 0+$1 . ".txt";

答案 2 :(得分:1)

我会修改你的正则表达式。尝试使用此代码:

my @list = ('R3_05_foo.txt','T3_12_foo_bar.txt','01.txt');

foreach (@list) {
    s/.*(\d{2}).*\.txt$/$1.txt/;
    s/^0+//;
    print $_ . "\n";
}

答案 3 :(得分:1)

问题在于s///中的第一部分与您认为的相符,但第二部分并未取代您认为应该的内容。 s///只会替换之前匹配的内容。因此,要替换像T3_这样的东西,你也必须匹配它。

s/.*(\d{2}).*\.txt$/$1.txt/;