且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在使用 Perl 进行搜索和替换期间,如何附加而不是替换文本?

更新时间:2023-09-14 12:17:40

这就是反向引用的用途.只需用括号将要捕获的文本部分括起来即可.第一组括号以 $1 提供,第二组以 $2 提供,依此类推.

This is what backreferences are for. Just surround the section of text you want to capture with parentheses. The first set of parentheses are available in $1, the second in $2, and so on.

s/(\s[0-9]\s[0-9]{3})/$1I/

使用 Perl 5.10,我们获得了命名捕获,所以你可以说

With Perl 5.10 we gained named captures, so you can say

s/(?<bodytext>\s[0-9]\s[0-9]{3})/$+{bodytext}I/

> 之间的东西是名字.名称成为 %+ 变量中的键,值是捕获的文本.

The stuff inbetween < and > is the name. Names become keys in the %+ variable and the values are the captured text.

另一种解决方案是使用 零宽度正向后视

Another solution is to use a zero-width positive look-behinds

s/(?<=\s[0-9]\s[0-9]{3})/I/

或其,Perl 5.10 的新内容,简写 \K

or its, new to Perl 5.10, shorthand \K

s/\s[0-9]\s[0-9]{3}\K/I/

试试

perl -pi -e 's/(\s[0-9]\s[0-9][0-9][0-9])/$1I/' filename

如果你使用双引号,$1 会在 Perl 看到它之前被 shell 插入.如果你认为应该工作的东西有问题,那么看看 Perl 看到的东西可能是个好主意.你可以用 B::Deparse:

If you use double quotes the $1 is interpolated by the shell before Perl ever sees it. If you have problems with something you think should work, it may be a good idea to take a look at what Perl is seeing. You can do this with B::Deparse:

perl -MO=Deparse -pi -e "s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/" filename

这将产生以下输出.

BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
    s/(\s[0-9]\s[0-9][0-9][0-9])/I/;
}
continue {
    print $_;
}
-e syntax OK

由此我们可以看到 $1 缺失.让我们用单引号再试一次:

From this we can see that $1 is missing. Lets try again with single quotes:

perl -MO=Deparse -pi -e 's/(\s[0-9]\s[0-9][0-9][0-9])/$1I/' filename
BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
    s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/;
}
continue {
    print $_;
}
-e syntax OK

还有一次转义:

perl -MO=Deparse -pi -e "s/(\s[0-9]\s[0-9][0-9][0-9])/\$1I/" filename
BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
    s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/;
}
continue {
    print $_;
}
-e syntax OK