根据某一行中的值获取多行输入文件

时间:2013-07-16 18:18:07

标签: perl

我正在慢慢学习更多PERL,并且需要一些我正面临的问题的帮助。我有一个以csv格式给出的excel电子表格中的输入文件。在电子表格中,如果行中的一个单元格值具有“LOV”,它们将合并单元格并给出值列表。我需要抓住与该LOV一起使用的下一行X行,然后将该LOV输出到一行,并使用同一行中的其他值。所以这是输入文件的样子:

Intro |Input|Middle |PPP|Requirement|Manual|Text|||
Intro |Input|END |PPP|Design|Manual|LOV|"Ancestory
Red
Blue
Purple
Orange
Yellow"||
Intro |Output|END |PPP|Design|Automatic|Number|||

该文件看起来像这样,只会重复与上面类似的数据。输出将根据Text,LOV,Number ETC放入不同的文件中。我需要让LOV输出显示如下:

Intro |END |LOV|"Ancestory Red Blue Purple Orange Yellow"||

我完全迷失了如何解决这个问题。我可以使用数组来获取引文中的下一行吗?我可以很好地抓住所有其他线路,但到目前为止这是我的逻辑看起来像。

my @LOV;
while(<file1>){

            my($line) = $_;
            chomp $line;
            if $line == "LOV"
            {

                push @LOV, $_;
                while (<file1>) 
                {
                    last if /^$/;
                    push @LOV, $_;
                }                       
                    print file2 "$output\n";
            }
            else
            {


                if ("NUMBER")
                {
                    print file3"output";
                }
                else if ("Text")
                {
                    print file4"output";
                }

            }

我不知道我是否应该以不同的方式阅读文件,但任何建议或帮助都会很棒!感谢您提供的一切。

1 个答案:

答案 0 :(得分:4)

好奇。你用什么书来学习Perl?

你的编码风格已经过时了。你不是第一个学习Perl并使用可以追溯到20世纪80年代后期的语法风格的人,所以我只是好奇人们用来学习Perl的市场(或网页)上的书。

Perl的一个奇妙之处在于它有许多模块可以处理你想要的大部分内容。在这种情况下,您需要使用Text::CSV模块,在阅读包含嵌入式NL的列时,将为您完成所有繁重的工作:

use warnings;
use strict;
use autodie;
use feature qw(say);

use Text::CSV;

my $spreadsheet = Text::CSV->new (
    {
        binary      => 1,
        sep_char    => "|",
        eol         => $/,
    }
);
open my $file, "<:crlf", "text.csv";

while ( my $row = $spreadsheet->getline($file) ) {
    my @columns = @{ $row };
    for my $field ( @columns ) {
        $field =~ s/\n/, /g;
    }
    say join " | ", @columns;
}

打印出来:

Intro  | Input | Middle  | PPP | Requirement | Manual | Text |  |  | 
Intro  | Input | END  | PPP | Design | Manual | LOV | Ancestory, Red, Blue, Purple, Orange, Yellow |  | 
Intro  | Output | END  | PPP | Design | Automatic | Number |  |  | 

不幸的是,它使用面向对象的符号,这可能有点令人困惑,但我会尝试将这一点一点一点地分开:

首先,您可能需要安装Text::CSV。您可以使用以下命令执行此操作:

$ cpan install Text::CSV

如果安装了Strawberry Perl或ActivePerl,这应该可以在Windows上正常工作。

如果您使用的是Linux或Mac,则需要执行此操作:

$ sudo cpan install Text::CSV

而且,您需要 root 密码。

安装完成后,如果您愿意,还可以安装Text::CSV_XS。这使得Text :: CSV更快,特别是如果你有非常非常大的电子表格。

让我们一行一行:

use开头的前四行是应该在所有程序中的标准编译指示。 strict将防止草率错误,warnings将帮助您捕获其他类型的错误,例如使用不包含任何值的变量。

my $spreadsheet = Text::CSV->new正在创建对象。这是您用来操作文件的内容。这有三个参数。 binary允许多行数据(就像你拥有的那样)。 sep_char表示您的分隔符不是逗号,而是|符号。我不太确定eol很重要 - 尤其是当我用<:crlf打开文件时我处理Unix / Windows问题,这会将crlf的实例转换为lf 1}}。

我打开文件并使用getline方法读取我的行。这将读入您的多个长行,而无需计算行数或任何内容。

在:

my @columns = @{ $rows };

有点棘手。 Perl变量都基于单个值。当然你有哈希和数组,但它们是单个值的列表。有时,您需要将值作为一个集处理,而Perl使用References。 $rows是指向我的列数组的指针。我解除引用引用并创建一个名为@columns的真实数组。有关详细信息,请阅读Reference Tutorial

$field =~ s/\n/, /g;只是用逗号替换字段中新行的任何实例。

最后,我只需使用say命令打印所有内容,然后使用join将我的行连接到一个字符串中,我可以打印出来并将它们|分开。< / p>

注意我不需要计算和处理多行行。 Text::CSV模块为我做了。它简短易懂,即使多个划线字段位于电子表格的中间,也能正常工作。