3

我有这个小脚本:

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

4 回答 4

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)表示后面没有数字

于 2013-07-23T11:46:19.880 回答
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";
于 2013-07-23T12:08:52.667 回答
1

问题是你的s///比赛的第一部分,你认为它做了什么,但第二部分并没有取代你认为它应该做的事情。s///只会替换之前匹配的内容。因此,要替换像T3_你这样的东西也必须匹配它。

s/.*(\d{2}).*\.txt$/$1.txt/;
于 2013-07-23T11:57:03.483 回答
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";
}
于 2013-07-23T11:51:14.587 回答