2010-02-22 141 views
7

我正在寻找一种方法来读取输入文件,并在Perl中只打印选择行到输出文件。我要打印到输出文件的行全部以xxxx.xxxx.xxxx开头,其中x是字母数字字符(周期是句点,而不是通配符)。线条并不都具有相同的结尾,如果这有所作为。我正在考虑类似以下内容(据我所知,if声明的条件完全是缺失的)。如何在Perl中只写一个文件的某些行?

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

在此先感谢!

回答

8

这是通过您的线路回路更好的办法。它避免了加载你的整个输入文件到内存中一次:

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/^ \w{4} \. \w{4} \. \w{4} /x; 
} 
close $fho; 
close $fhi; 

记住的是,\w字符类还包括下划线。为了避免下划线:

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

您可能想要为该第二个正则表达式添加'/ i'修饰符以及... – 2010-02-22 22:48:56

+1

谢谢!唯一缺少的是在'if'语句中的'$ fho'后面的'$ _'(花了我一段时间才发现,实际上...) – ryantmer 2010-02-22 22:55:19

+1

@ryantmer:是的,我的代码没有经过测试。我更新了我的帖子。我懒得创建任何虚假输入来测试我的代码,这就是为什么提供一个小样本输入与您的问题是一个好主意。 – toolic 2010-02-22 23:41:50

1
if ($_ =~ m/^\w{4}\.\w{4}\.\w{4}/i) 

认为。我的perl有点生疏。

0

如果你不介意把它当作一个命令行1班轮:

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

风格提示:

  • 使用词法文件句柄
  • 检查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 /^\w{4}\.\w{4}\.\w{4}/; 
} 

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

用grep

grep "^\w\{4\}\.\w\{4\}\.\w\{4\}\b" file 
+1

这是在命令行上,而不是在perl BTW。这就是'grep'的意义所在。如果你没有现代的'grep',你可能需要'egrep'或像'^ [0-9a-zA-Z。] {14}'这样的更老的正则表达式。 – Nathan 2010-02-23 00:54:30

+0

是的,在命令行上。我假设'grep'标签是* nix grep,而不是Perl自己的。 – ghostdog74 2010-02-23 00:56:13

0
perl -ne 'print if /^\w{4}\.\w{4}\.\w{4}\b/' file > newfile.csv 
1

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

接近$出; 在该基本表单中,添加您需要插入,更改或删除行的部分。

要在行首添加行,请在输入打印现有行的循环之前打印这些行。

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; 要更改现有行,请插入代码以修改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; 要仅更改特定行,输入行号$。是有用的。首先阅读并打印您想要更改的行。接下来,阅读您想要更改的单行,更改并打印它。之后,阅读其余的行并打印这些行:

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的和领带::文件可以提供帮助的了。但是,如果可以,请避免一次读取整个文件。在这个过程完成之前,Perl不会将该内存返回给操作系统。

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

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

为了inFile.txt的备份,给-ia文件扩展名补充:

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 
相关问题