我有这个小脚本:
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
的字符串开头。
答案 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/;