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

Posted

技术标签:

【中文标题】逐行读取文件并替换字符串,打印到文件【英文标题】:Read a file line by line and replace a string, print to out file 【发布时间】:2019-01-29 12:29:03 【问题描述】:

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

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";
  

此脚本旨在替换所有内容并将文件放入带有更改的替换文件夹中......这不起作用,它给出了错误......我如何替换和打印相同的所有文件当前目录..

【问题讨论】:

你能把错误贴在这里吗? @GerhardBarnard 是的,我和你说的一样 只是想用 name('filename') 替换例如 name() 在我看来,如果有人有错误,他/她至少可以把错误放在问题上。即使问题很明显。 我终于编辑了问题并添加了 myslef 的错误。请,对于未来的问题,请始终包含您遇到的错误。 【参考方案1】:

直接错误和危险信号:

一旦分配了while ($variable = &lt;$fh&gt;)$_没有设置为&lt;$fh&gt; 读取的内容;它保持原样(此处未定义);因此,与它匹配的正则表达式(默认情况下)将不起作用

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

1234563 p>

我假设./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;启动程序

&lt;*&gt; 读取当前目录中的所有条目,有什么困难的问题;一方面,这可能包括脚本本身。更重要的是,这样您的脚本就可以与要处理的数据进行硬连线。为什么不接受用户输入呢?我将其更改为使用在命令行上提交的内容,大概是文件名。然后在 Linux 上,您可以将脚本调用为

script.pl *.ext

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

始终根据需要检查输入。在这种情况下,您至少可以确保只处理普通文件。我只是使用-ffiletest operator 过滤,但另一种选择是将输入作为提交然后检查,以便您可以通知用户输入不足

我觉得没必要介绍$filename;只需使用主题工具$file

如果您使用 UTF8,最好使用 open pragma;然后处理所有文件和流

对所有内容都使用词法文件句柄,因此也可以写入文件

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

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

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

原则上,使用qr operator 将模式定义为单独的变量是个好主意。然后您可以使用 quotemeta

转义其中的所有特殊字符

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

【讨论】:

【参考方案2】:

您可以尝试以下方法吗?我假设在当前工作目录中找到了“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";

强制更改:

    过滤 (grep) &lt;*&gt; 以便我们丢弃目录。如果没有,您将在尝试打开目录时遇到权限错误 正则表达式上的花格(匹配)括号到\( 修复代码中的一个错误,即您逐行匹配文件但您替换了$_ 变量而不是$variable。现在它总是与$_一起工作 修复了最后一个正则表达式,它有一些不需要的括号 您必须打印“完成!”在 while 循环之外,因为该 while 是针对每一行的。

建议的更改:

    添加了use strictuse warnings非常推荐) 使用英文并引用$!$OS_ERRORmy添加到foreach的变量中 读/写后关闭文件。 如果“replaced”文件夹不存在,则创建它 对于输出文件,使用词法文件句柄和 3 参数打开 open my $newfh, '&gt;', ...

【讨论】:

以上是关于逐行读取文件并替换字符串,打印到文件的主要内容,如果未能解决你的问题,请参考以下文章

python读取文本文件,如何将每行最后一个特定字符替换?

Java之修改文件内容:字符串逐行替换

python替换txt文件中固定内容

在文件中搜索 printf 语句并替换为字符串值

Python 正则表达式替换匹配文本

查找和替换文件中的单词/行