从文件中提取数据

时间:2014-03-24 06:15:38

标签: perl csv text extract

我有像

这样的数据
"scott
E -45  COLLEGE LANE
BENGALI MARKET
xyz  -785698."
"Tomm
D.No: 4318/3,Ansari Road, Dariya Gunj,
xbc - 289235."

我编写了一个Perl程序来提取名称,即

open(my$Fh, '<', 'printable address.txt') or die "!S";
open(my$F, '>', 'names.csv') or die "!S";
while (my@line =<$Fh> ) {
    for(my$i =0;$i<=13655;$i++){
        if ($line[$i]=~/^"/) {
        print $F $line[$i];
        }

    }
}

它工作正常,它精确地提取名称。现在我的目标是提取类似

的地址
BENGALI MARKET
xyz  -785698."
D.No: 4318/3,Ansari Road, Dariya Gunj,
xbc - 289235."

在CSV文件中。怎么做请告诉我

1 个答案:

答案 0 :(得分:0)

原始问题存在很多缺陷。在提出任何改进之前应该解决这些问题:

  1. 始终在每个脚本的顶部都有use strict;use warnings;
  2. 您的or die "!S"语句已损坏。错误代码实际上在$!中。但是,您可以通过use autodie;
  3. 跳过这样做的需要
  4. 为您的文件句柄提供更有意义的名称。 $Fh$F没有说明这些内容。至少将它们标记为$infh$outfh
  5. while (my @line = <$Fh>) {存在缺陷,因为它可以缩减为my @line = <$Fh>;。因为你要在列表上下文中读取readline,它会使整个文件出现问题,然后它会退出下一个循环。相反,将它分配给标量,你甚至不需要下一个for循环。
  6. 如果您想将整个文件粘贴到@line,那么您对for(my$i =0;$i<=13655;$i++){的使用也存在缺陷。您应该迭代到@line的最后一个索引,即$#line
  7. if ($line[$i]=~/^"/) {也存在缺陷,因为您将引号字符"留在您要匹配的名称的开头。而是添加一个捕获组来提取名称。
  8. 根据建议的更改,代码将缩减为:

    use strict;
    use warnings;
    use autodie;
    
    open my $infh, '<', 'printable address.txt';
    open my $outfh, '>', 'names.csv';
    
    while (my $line = <$infh>) {
        if ($line =~ /^"(.*)/) {
            print $outfh "$1\n";
        }
    }
    

    现在,如果您还想隔离地址,可以使用与名称相似的方法。我将假设您可能希望在变量中构建整个地址,以便您可以执行更复杂的操作,而不是将它们盲目地放在文件中。但是,现在镜像文件设置:

    use strict;
    use warnings;
    use autodie;
    
    open my $infh, '<', 'printable address.txt';
    open my $namefh, '>', 'names.csv';
    open my $addressfh, '>', 'address.dat';
    
    my $address = '';
    
    while (my $line = <$infh>) {
        if ($line =~ /^"(.*)/) {
            print $namefh "$1\n";
    
        } elsif ($line =~ /(.*)"$/) {
            $address .= $1;
            print $addressfh "$address\n";
            $address = '';
    
        } else {
            $address .= $line;
        }
    }
    

    最终,无论您想要使用什么数据,最佳解决方案都可能是使用Text::CSV将其输出到真实的CSV文件。这样就可以非常轻松地将其导入到电子表格或其他系统中,您无需再次解析它。

    use strict;
    use warnings;
    use autodie;
    
    use Text::CSV;
    
    my $csv = Text::CSV->new ( { binary => 1, eol => "\n" } ) 
        or die "Cannot use CSV: ".Text::CSV->error_diag ();
    
    open my $infh, '<', 'printable address.txt';
    open my $outfh, '>', 'address.csv';
    
    my @data;
    
    while (my $line = <$infh>) {
        # Name Field
        if ($line =~ /^"(.*)/) {
            @data = ($1, '');
    
        # End of Address        
        } elsif ($line =~ /(.*)"$/) {
            $data[1] .= $1;
            $csv->print($outfh, \@data);
    
        # Address lines     
        } else {
            $data[1] .= $line;
        }
    }