PERL:文件中的字符串替换

时间:2014-02-10 00:41:31

标签: perl replace

我正在编写一个脚本来在文件中进行字符串替换,我将从配置文件中读取变量,值和文件并进行字符串替换。

这是我做字符串替换的逻辑。

sub expansion($$$){
my $f = shift(@_) ; # file Name
my $vname = shift(@_) ; # variable name for pattern match
my $value = shift(@_) ; # value to replace
my $n = "$f".".new";

    open ( O, "<$f") or   print( "Can't open $f file: $!");
    open ( N ,">$n" ) or print( "Can't open $n file: $!");
    while (<O>)
    {
        $_ =~ s/$vname/$value/g;  #check for pattern
        print N "$_" ;
    }
    close (O);
    close (N);


}

在我的逻辑中,我从输入文件($ f)逐行读取模式并写入新文件($ n)。

当我尝试执行相同的操作时,有没有办法在原始文件中替换原始文件,而不是写入新文件,只有空文件没有内容。

2 个答案:

答案 0 :(得分:2)

不要。从不, 1 。你不敢,甚至不想,不要使用子程序原型。它被严重破坏(也就是说,它没有按照你的想法做到)并且是dangerous


现在,我们已经解决了这个问题:

是的,你可以做你想做的事。您可以使用模式<+ open将文件作为可读写文件。到目前为止,非常好。

但是,由于缓冲,您无法使用标准的读写方法来读取和写入文件。相反,您需要使用sysreadsyswrite

然后,您需要做的是阅读,使用sysseek返回到您阅读的位置的开头,然后写入该位置。

这不仅非常复杂,而且充满了危险。我们举一个简单的例子。我有一个文档,我想用直引号替换我的卷引号。

$line =~ s/“|”/"/g;

那应该有用。我正在用另一个角色替换一个角色。怎么可能出错?

如果这是一个UTF-8文件(默认情况下Mac和Linux系统使用),那些引号是双字节字符,而直引号是单字节字符。我会写回一条比我读入的更短的。我的缓冲区将会关闭。

回到以千字节为单位测量计算机内存和存储的日子,以及像卷到卷磁带这样的串行设备,这种类型的操作非常普遍。然而,在这个存储空间庞大的时代,这种复杂性和容易出错的过程根本不值得。坚持从一个文件读取,并写入另一个文件。然后使用unlinkrename删除原始文件,并将副本重命名为原始名称。

更多指示:

  • 如果无法打开文件,请不要print。使用die。否则,您的程序将继续轻快地意识到它无法正常工作。更好的是,使用编译指示use autodie;,您不必担心测试读/写是否失败。

  • 将标量用于文件句柄。

而不是

open OUT, ">my_file.txt";

使用

open my $out_fh, ">my_file.txt";
  • 并且,强烈建议使用三个参数open:

使用

open my $out_fh, ">", "my_file.txt";
  • 如果不是,请务必添加use strict;use warnings;

事实上,你的Perl语法有点古老。你需要在Modern Perl上找一本书。 Perl最初是用hack语言编写的,用来取代shell和awk编程。但是,Perl已经演变成一种完整的语言,可以处理复杂的数据类型,面向对象和大型项目。学习Perl的现代语法将帮助您找到错误,并成为更好的开发人员。


1。像所有规则一样,这可以被打破,但前提是你清楚而仔细地了解正在发生的事情。这就像那些说“不要在家里这样做的节目。我们是专业人士。”

答案 1 :(得分:0)

sub inplace_expansion($$$){
    my $f = shift(@_) ; # file Name
        my $vname = shift(@_) ; # variable name for pattern match
        my $value = shift(@_) ; # value to replace

    local @ARGV = ( $f );
    local $^I = '';
    while (<>)
    {
        s/\Q$vname/$value/g;  #check for pattern
        print;
    }
}

或者,我的偏好会更接近于此(基本上相当于,主要在格式化,变量名称等方面进行更改):

use English;
sub inplace_expansion {
  my ( $filename, $pattern, $replacement ) = @_;
  local @ARGV = ( $filename ),
        $INPLACE_EDIT = '';
  while ( <> ) {
    s/\Q$pattern/$replacement/g;
    print;
  }
}

local的技巧基本上模拟了一个命令行脚本(就像用perl -e运行一样);有关详细信息,请参阅perldoc perlrun。有关$^I(又名$INPLACE_EDIT)的更多信息,请参阅perldoc perlvar

(对于\Q的商家(在s//表达式中),请参阅perldoc -f quotemeta。这与您的问题无关,但很有用。另请注意传递正则表达式模式在变量周围 - 而不是,例如,仅使用文字正则表达式 - 可能容易受到注入攻击; Perl的内置taint mode在这里很有用。)

编辑:David W. right关于原型。