逐行读取文件并替换字符串,打印到文件

Read a file line by line and replace a string, print to out file

目前我正在使用以下代码来查找字符串替换字符串并将其打印到与文件中的名称相同但在替换文件夹中的输出文件

use Tie::File;
@files = <*>;
foreach $file (@files) {
    my $filename = $file;
    open(my $fh, '<:encoding(UTF-8)', $filename) or die "Could not open file '$filename' $!";
    open(NEWFILE,"> ./replaced/$filename");

   while(my $variable=<$fh>){

      s/Insertstoredprocedure ( / Insertstoredprocedure('$filename',/g;
      s/SuccessSp()/SuccessSp()('$filename')/g;

  print NEWFILE "$variable";
  print "done\n";
  }
}

此脚本旨在替换所有内容并将文件放入包含更改的替换文件夹中....这不起作用它会出错...我如何替换并打印所有内容当前目录中的文件..

你能试试下面的吗?我假设在当前工作目录中找到 'replaced'。

use strict;
use warnings;
use Tie::File;
use English qw(-no_match_vars);

my @files = grep {-f} <*>;

-d './replaced/' or mkdir './replaced/';

foreach my $file (@files) {
    open my $fh, '<:encoding(UTF-8)', $file
      or die "Could not open file '$file': $OS_ERROR";
    open my $newfh, '>', "./replaced/$file"
      or die "Could not create new file './replaced/$file': $OS_ERROR";
    while (<$fh>) {
        s/Insertstoredprocedure\s*\(/Insertstoredprocedure('$file'/g;
        s/SuccessSp\s*\(/SuccessSp('$file'/g;
        print {$newfh} $_;
    }
    close $fh or die $OS_ERROR;
    close $newfh or die $OS_ERROR;
    print 'DONE with file: '.$file."\n";
}

强制更改:

  1. filter (grep) <*> 以便我们丢弃目录。否则,您将在尝试打开目录时遇到权限错误
  2. 正则表达式上的 Scape(匹配)括号 \(
  3. 修复代码中逐行匹配文件但替换了 $_ 变量而不是 $variable 的错误。现在它总是与 $_
  4. 一起工作
  5. 修复了最后一个正则表达式,它有一些不需要的括号
  6. 您必须在 while 循环之外打印 'Done!',因为 while 是针对每一行的。

建议更改:

  1. 添加了use strictuse warnings非常推荐
  2. 使用英文并引用 $! 作为 $OS_ERROR
  3. 添加my到foreach
  4. 的变量
  5. 关闭文件一次read/written。
  6. 如果 'replaced' 文件夹不存在则创建
  7. 对于输出文件,使用词法文件句柄和 3 参数打开 open my $newfh, '>', ...

直接错误和危险信号:

  • 一旦您分配 while ($variable = <$fh>)$_ 未设置为 <$fh> 读取的内容 ;它保持原样(此处未定义);所以你的正则表达式(默认情况下)将不起作用

  • 要在正则表达式中匹配为文字字符的括号需要转义

  • 代码处理当前目录中的所有文件,<*>——在这段代码中也可能包含脚本本身,并且 没有守卫或检查

我假设 ./replaced/ 你的意思是 replaced/ 在脚本所在的目录中,而不是在当前工作目录中(如 pwd);这些通常是不一样的。请澄清。

已更正,有其他更改

use warnings;
use strict;
use feature qw(say);

use FindBin qw($RealBin);

use open ':std', ':encoding(UTF-8)';

my @files = grep { -f } @ARGV;    # add further checks of user input

my $outdir = "$RealBin/replaced";
mkdir $outdir if not -d $outdir;  # or use File::Path

foreach my $file (@files) {
    my $fout = "$outdir/$file";
    open my $fh, '<', $file or die "Can't open $file: $!";
    open my $fh_out, '>', $fout or die "Can't open $fout: $!";

    while (my $line = <$fh>) {
        $line =~ s/Insertstoredprocedure \( / Insertstoredprocedure('$file',/g;
        $line =~ s/SuccessSp\(\)/SuccessSp()('$file')/g;

        print $fh_out $line;
    }
    say "done, $file --> $fout";
}

对问题中代码的评论

  • 始终use warnings;use strict;

  • 启动程序
  • <*>读取当前目录下的所有条目,有什么难的问题;其中之一,可能包括脚本本身。更重要的是,通过这种方式,您的脚本与要处理的数据是硬连接的。为什么不接受用户输入呢?我将其更改为使用在命令行上提交的内容,大概是文件名。然后在 Linux 你可以调用脚本作为

    script.pl *.ext
    

    如果必须,您仍然可以使用 script.pl *,但是您需要进行更多检查,特别是要确保跳过脚本本身(如果 运行 来自其目录)。例如参见 [​​=34=]

  • 始终根据需要检查输入。在这种情况下,您至少可以确保只处理普通文件。我只是使用 -f filetest operator 进行过滤,但另一种选择是接受已提交的输入然后进行检查,这样您就可以通知用户输入不足

  • 我看没必要介绍$filename;只需使用主题化剂 $file

  • 如果您使用 UTF8 更好地使用 open pragma;然后所有文件和流都得到处理

  • 对所有内容都使用词法文件句柄,因此对于要写入的文件也是如此

  • 从文件中读取一行时为什么不调用它$line?代码中的“$variable”非常通用,以至于它没有提供有关该变量是什么的线索

  • 一旦你在 while 条件下赋值给命名变量,那么 $_ 不会设置为读取的内容;只有 while (<$fh>) 才会发生这种情况。在此代码中,它在循环体内是未定义的。因此,在正则表达式中,您需要使用 that 变量, 分配给该变量(而不是将其保留为默认值 $_

  • 如果要将正则表达式中具有特殊含义的字符作为文字字符进行匹配,则必须对其进行转义,括号就是其中之一。有很多种方法,我用你的文字直接用\转义(替换部分不用转义)

  • 原则上,使用 qr operator. Then you can escape all special characters in them using quotemeta

  • 将模式定义为单独的变量是个好主意

我无法知道您的(更正后的)正则表达式是否符合预期,所以我只能修复明显的错误。请显示数据样本和所需输出。