【问题标题】:PERL: String Replacement on filePERL:文件上的字符串替换
【发布时间】:2014-02-10 00:41:31
【问题描述】:

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

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

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)。

当我尝试做同样的事情时,有什么方法可以替换原始文件而不是写入新文件,它只有空文件而没有内容。

【问题讨论】:

  • perl 有一个 exp 内置函数;为您的子选择另一个名称。另外,不要使用原型;它们的设计目的不是做其他语言中的原型所做的事情,没有它们你会过得更好。
  • 有什么东西阻止你将新文件复制到旧文件名?
  • 我更新了函数名称,即使在我的原始脚本中我使用了不同的名称..感谢指出。
  • @TLP :实际上,一旦替换完成,我就会将新的复制到旧的,但是我想对用户做一个差异(用于预览选项),它只适用于一个字符串替换文件以防万一我有多个文件和多个变量要替换我想知道它不会锻炼.. 那么有没有办法做其他替换方法..
  • 不太清楚你在说什么。如果只更改原始文件,为什么做差异会更容易?你需要两个文件来做一个差异。

标签: perl replace


【解决方案1】:

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


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

是的,你可以为所欲为。您可以使用&lt;+ 模式将open 文件作为可读写的文件。到目前为止,一切顺利。

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

然后,你需要做的是阅读,使用sysseek回到你阅读的开头,然后写到那个地方。

不仅做起来很复杂,而且充满危险。让我们举一个简单的例子。我有一个文档,我想用直引号替换我的弯引号。

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

应该可以。我正在用另一个字符替换一个字符。会出什么问题?

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

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

还有几点建议:

  • 如果文件无法打开,请不要print。使用die。否则,您的程序将继续愉快地继续运行,而不会意识到它不起作用。更好的是,使用 pragma 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. 像所有规则一样,这可以被打破,但前提是你清楚而仔细地了解正在发生的事情。就像那些节目说“不要在家里这样做。我们是专业人士。”

【讨论】:

    【解决方案2】:
    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 关于原型的。

    【讨论】:

      猜你喜欢
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-30
      • 2013-07-17
      • 2014-10-06
      • 2012-09-21
      • 1970-01-01
      相关资源
      最近更新 更多