Perl就地替换

时间:2019-08-29 05:42:20

标签: regex perl

在Perl衬里中,我们可以使用-i参数进行就地替换。在IDE中编写Perl代码时,-i的等效功能是什么?

考虑以下代码:

binmode(STDOUT, ':raw');
open my $fh, '<', $filename;
while (<$fh>) {
    s/^/<rootroot>/ if $.==1;
    if (/(<link rel[^<>\n]*?)(\/?)(>)/g) {
        my ($p1, $p2, $p3) = ($1, $2, $3);
        s/$p1$p2$p3/($p2 ? qq|$p1$p2$p3<span class="entry">| : qq|$p1\/$p3<span class="entry">|)/ge;
    };
    s/<\/>/<entry_end><\/entry_end>/;
    s/$/<\/rootroot>/ if eof;

}

如何将所有更改行保存到位?

因为我需要在就地更改html源代码后立即使用XML :: LibXML对html文件进行快速验证。

先谢谢了。

1 个答案:

答案 0 :(得分:2)

您可以尝试以下操作:

my $filename = 'test.dat';
@ARGV = ($filename);
$^I = '';
while(<<>>) {
    binmode(ARGV, ':raw');
    # Do the substitiution on $_ here ...
    print;
}

我没有找到如何在循环之前设置binmode的方法,因为ARGV仅在使用<>运算符之后才定义。

  • $^IARGV变量在perlvar

  • 中描述
  • 有关为什么应使用<<>>而非<>的信息,请参见perlop

一些注意事项:

  • while(<>) { ... } 根据{{​​3}},循环
while (<>) {  ...         # code for each line
}
     

等效于以下类似Perl的伪代码:

unshift(@ARGV, '-') unless @ARGV;   
while ($ARGV = shift) { 
    open(ARGV, $ARGV);
    while (<ARGV>) {    
       ...        # code for each line    
    }  
}  
  • 使用不带备份文件的就地编辑:$^I=""

根据perlop

  

如果未提供扩展名,并且您的系统支持,则原始   输出重定向到文件时,文件保持打开状态且没有名称   具有原始文件名的新文件。无论Perl是否干净地退出,   原始文件已取消链接。

以及perlrun博客中的更多信息:

  

Perl打开并立即取消链接原始文件,然后打开一个   具有相同名称的新文件(新文件描述符和索引节点),并发送   输出到第二个文件;最后,关闭旧文件,   由于已取消链接而被删除,剩下的就是更改   与原始文件同名的文件。

有关实际实现,另请参见this

  • 根据上述情况,可能会发生以下情况:

    my $fn = 'test.dat';
    open ( my $fh, '<:raw', $fn ) or die "Could not open file '$fn': $!";
    unlink $fn or die "$!";
    open ( my $fh2, '>:raw', $fn ) or die "Could not reopen file '$fn': $!";
    while(<$fh>) {
        # Do the substitutions on $_ here ...
        print $fh2 $_;
    }
    close $fh;
    close $fh2;