1

我正在慢慢地学习更多关于 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";
                }

            }

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

4

1 回答 1

4

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

您的编码风格已经过时了。您不是第一个学习 Perl 并且使用可追溯到 1980 年代后期的语法风格的人,所以我只是好奇市场上有哪些书籍(或网页)可供人们用来学习 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很重要——尤其是当我打开文件时会处理 Unix/Windows 问题,该文件<:crlf会将.crlflf

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

这:

my @columns = @{ $rows };

有点棘手。Perl 变量都基于单个值。当然你有散列和数组,但它们是单个值的列表。有时,您需要将值作为一个集合来处理,而 Perl 使用引用。$rows是指向我的列数组的指针。我正在取消引用引用并创建一个名为@columns. 阅读参考教程以获取更多信息。

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

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

请注意,我不需要计算和处理多行行。该Text::CSV模块为我做。它简短易懂,即使多行字段位于电子表格的中间,也可以使用。

于 2013-07-16T19:00:24.130 回答