在Perl中压缩文件时如何跳过行?

Joe*_*Joe 6 perl

我怎样才能做到这一点?

open FILE, $somefile;
foreach (<FILE>)
{
   if (/some_regex/)
   {
      $want_the_next_line = <FILE>;
      $want_the_next_line_after_that = <FILE>;
   }
}
Run Code Online (Sandbox Code Playgroud)

明白我的意思了吗?我基本上想要在我的foreach中间插入一堆线,而不是必须记住我的状态并在每次迭代时检查它.而我目前在Perldoc的<>上找不到任何有用的东西.

哦,顺便说一句,我真的不想:

@file = <FILE>;
Run Code Online (Sandbox Code Playgroud)

我相信你明白了.

Dav*_*itt 11

使用while而不是foreach:

open FILE, $somefile;
while (<FILE>)                      # <<-- HERE
{
   if (/some_regex/)
   {
      $want_the_next_line = <FILE>;
      $want_the_next_line_after_that = <FILE>;
   }
}
Run Code Online (Sandbox Code Playgroud)

while循环将只读取一行<FILE>,然后你可以做你的当前迭代希望它.

此技术还可以帮助您避免一次读取整个文件.

技术背景: foreach()需要一个数组,因此一次读取整个文件,而while()循环中的表达式是标量上下文,只检查"假"值,就像EOF产生的那样.

  • 早上9点35分在欧洲.欢迎来到全球化. (2认同)
  • +1.一个警告:不像foreach,而clobbers $ _,所以你可能想要"本地$ _;" 预先. (2认同)
  • @Jon:无论如何,不​​要打扰30行剧本.在较大的项目中,总是确保你的函数不会破坏$ _(或任何其他全局状态)的好处是,你不必考虑从任何地方调用它们是否安全 - 甚至是最内层的循环.基本上它会删除您需要记住的有关函数的一种信息. (2认同)

bri*_*foy 5

您可以在perlfaq5中使用相同的技术:如何更改,删除或插入文件中的行,或附加到文件的开头?:


(由brian d foy提供)

从文本文件中插入,更改或删除行的基本思想包括读取和打印文件到要进行更改的位置,进行更改,然后读取和打印文件的其余部分.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 $_;
    }

    close $out;
Run Code Online (Sandbox Code Playgroud)

在该基本表单中,添加您需要插入,更改或删除行的部分.

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

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 $_;
    }

    close $out;
Run Code Online (Sandbox Code Playgroud)

要更改现有行,请插入代码以修改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 $_;
    }

    close $out;
Run Code Online (Sandbox Code Playgroud)

要仅更改特定行,输入行号$.是有用的.首先阅读并打印到您想要更改的行.接下来,阅读您要更改的单行,更改并打印它.之后,阅读其余部分并打印出来:

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 $_;
    }
Run Code Online (Sandbox Code Playgroud)

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

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

通过使用next跳过您不想在输出中显示的行来删除特定行也是同样的事情.此示例跳过每五行:

while( <$in> )
    {
    next unless $. % 5;
    print $out $_;
    }
Run Code Online (Sandbox Code Playgroud)

如果由于一些奇怪的原因,你真的想要一次看到整个文件而不是逐行处理,你可以将它啜饮(只要你能将整个文件放在内存中!):

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;
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

要备份inFile.txt,请添加-ia文件扩展名以添加:

perl -pi.bak -e 's/Fred/Barney/' inFile.txt
Run Code Online (Sandbox Code Playgroud)

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

perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt
Run Code Online (Sandbox Code Playgroud)

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

perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt
Run Code Online (Sandbox Code Playgroud)

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

perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt
Run Code Online (Sandbox Code Playgroud)

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

perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt
Run Code Online (Sandbox Code Playgroud)

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

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

    ... or ...

perl -pi -e 'next unless /d/' inFile.txt
Run Code Online (Sandbox Code Playgroud)