如何在 Perl 中只写文件的某些行?

Posted

技术标签:

【中文标题】如何在 Perl 中只写文件的某些行?【英文标题】:How can I write only certain lines of a file in Perl? 【发布时间】:2011-01-19 20:42:20 【问题描述】:

我正在寻找一种在 Perl 中读取输入文件并仅将选定行打印到输出文件的方法。我要打印到输出文件的行都以xxxx.xxxx.xxxx 开头,其中x 是一个字母数字字符(句点是句点,而不是通配符)。如果这会有所不同,这些行并不都有相同的结尾。我在想类似以下的事情(据我所知,if 语句的条件是真正缺少的)。

open(IN, "<$csvfile");
my @LINES = <IN>;
close(IN);
open(OUT, ">$csvnewfile");
print OUT @LINES if ([line starts with xxxx.xxxx.xxxx]);
close(OUT);

提前致谢!

【问题讨论】:

【参考方案1】:

这里有一个更好的方法来循环你的行。它避免了一次将整个输入文件加载到内存中:

use strict;
use warnings;

open my $fhi, '<', $csvfile    or die "Can not open file $csvfile: $!";
open my $fho, '>', $csvnewfile or die "Can not open file $csvnewfile: $!";
while (<$fhi>) 
    print $fho $_ if m/^ \w4 \. \w4 \. \w4 /x;

close $fho;
close $fhi;

请记住,\w 字符类还包括下划线。为避免使用下划线:

print $fho $_ if m/^ [a-z\d]4 \. [a-z\d]4 \. [a-z\d]4 /xi;

【讨论】:

【参考方案2】:

风格提示:

使用词法文件句柄 查看open的结果 在打开写入的句柄上检查close 的结果也是一个好主意

见下文:

#! /usr/bin/perl

use warnings;
use strict;

die "Usage: $0 old new\n" unless @ARGV == 2;

my($csvfile,$csvnewfile) = @ARGV;

open my $in,  "<", $csvfile    or die "$0: open $csvfile: $!";
open my $out, ">", $csvnewfile or die "$0: open $csvnewfile: $!";

while (<$in>) 
  print $out $_ if /^\w4\.\w4\.\w4/;


close $out or warn "$0: close $csvnewfile: $!";

【讨论】:

【参考方案3】:

使用 grep

 grep "^\w\4\\.\w\4\\.\w\4\\b" file

【讨论】:

那是在命令行上,而不是在 perl 顺便说一句。这就是grep 的用途。如果您没有现代的grep,您可能需要egrep 或像^[0-9a-zA-Z.]14 这样的旧正则表达式或其他。 是的,在命令行上。我假设 grep 标记是 *nix grep,而不是 Perl 自己的。【参考方案4】:
if ($_ =~ m/^\w4\.\w4\.\w4/i)

认为。我的 perl 有点生疏了。

【讨论】:

【参考方案5】:

来自perlfaq5对How do I change, delete, or insert a line in a file, or append to the beginning of a file?的回复


在文本文件中插入、更改或删除一行的基本思想包括读取并打印文件到要进行更改的位置,进行更改,然后读取并打印文件的其余部分。 Perl 不提供对行的随机访问(特别是因为记录输入分隔符 $/ 是可变的),尽管 Tie::File 等模块可以伪造它。

执行这些任务的 Perl 程序采用打开文件、打印其行、然后关闭文件的基本形式:

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

while( <$in> )
    
    print $out $_;
    

关闭 $out; 在该基本表单中,添加您需要插入、更改或删除行的部分。

要将行添加到开头,请在进入打印现有行的循环之前打印这些行。

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC

while( <$in> )
    
    print $out $_;
    

关闭 $out; 要更改现有行,请插入代码以修改 while 循环内的行。在这种情况下,代码会找到“perl”的所有小写版本并将它们大写。每一行都会发生这种情况,因此请确保您应该在每一行上都这样做!

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n";

while( <$in> )
    
    s/\b(perl)\b/Perl/g;
    print $out $_;
    

关闭 $out; 要仅更改特定行,输入行号 $. 很有用。首先阅读并打印要更改的行。接下来,读取要更改的单行,更改并打印。之后,阅读其余的行并打印出来:

while( <$in> )   # print the lines before the change
    
    print $out $_;
    last if $. == 4; # line number before change
    

my $line = <$in>;
$line =~ s/\b(perl)\b/Perl/g;
print $out $line;

while( <$in> )   # print the rest of the lines
    
    print $out $_;
    

要跳过行,请使用循环控件。本示例中的下一个跳过注释行,最后一个在遇到 ENDDATA 时停止所有处理。

while( <$in> )
    
    next if /^\s+#/;             # skip comment lines
    last if /^__(END|DATA)__$/;  # stop at end of code marker
    print $out $_;
    

执行相同的操作来删除特定行,方法是使用 next 跳过您不想在输出中显示的行。此示例每隔五行跳过一次:

while( <$in> )
    
    next unless $. % 5;
    print $out $_;
    

如果出于某种奇怪的原因,您真的想立即查看整个文件而不是逐行处理,则可以将其吞入其中(只要您可以将整个文件放入内存中!):

open my $in,  '<',  $file      or die "Can't read old file: $!"
open my $out, '>', "$file.new" or die "Can't write new file: $!";

my @lines = do  local $/; <$in> ; # slurp!

    # do your magic here

print $out @lines;

File::Slurp 和 Tie::File 等模块也可以提供帮助。但是,如果可以,请避免一次读取整个文件。在进程完成之前,Perl 不会将该内存归还给操作系统。

您还可以使用 Perl 单行代码就地修改文件。以下将 inFile.txt 中的所有“Fred”更改为“Barney”,用新内容覆盖文件。使用 -p 开关,Perl 会在你用 -e 指定的代码周围包裹一个 while 循环,而 -i 会打开就地编辑。当前行在 $ 中。使用 -p,Perl 会在循环结束时自动打印 $ 的值。有关详细信息,请参阅 perlrun。

perl -pi -e 's/Fred/Barney/' inFile.txt

要备份 inFile.txt,请给 -i 一个要添加的文件扩展名:

perl -pi.bak -e 's/Fred/Barney/' inFile.txt

如果只更改第五行,可以添加一个测试检查$.,输入行号,然后只在测试通过时执行操作:

perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt

要在某行之前添加行,您可以在 Perl 打印 $_ 之前添加一行(或多行!):

perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt

您甚至可以在文件的开头添加一行,因为当前行打印在循环的末尾:

perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt

要在文件中已有的行之后插入一行,请使用 -n 开关。它就像 -p 一样,只是它不会在循环结束时打印 $_ ,所以你必须自己做。在这种情况下,先打印 $_,然后打印要添加的行。

perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt

要删除行,只打印您想要的行。

perl -ni -e 'print unless /d/' inFile.txt

    ... or ...

perl -pi -e 'next unless /d/' inFile.txt

【讨论】:

【参考方案6】:

如果您不介意将其保留为命令行 1 衬里:

perl -ne "print if /^.4[.].4[.].4/" csvfile.csv > csvnewfile.csv

【讨论】:

【参考方案7】:
perl -ne 'print if /^\w4\.\w4\.\w4\b/' file > newfile.csv

【讨论】:

以上是关于如何在 Perl 中只写文件的某些行?的主要内容,如果未能解决你的问题,请参考以下文章

如何查询某些行的sqlite,即将它分成页面(perl DBI)

如何在 swift 2.0 中只允许 UITextfield 中的某些数字集

WPF .Net 4 - OneWayToSource 绑定到只写属性适用于某些机器!如何?

WPF .Net 4 - OneWayToSource 绑定到只写属性适用于某些机器!如何?

如何从 Perl 中的 2 个文件之一中删除公共行?

如何从命令行测试Perl CGI脚本的文件上传?