读取包含换行符的CSV文件

3
我正在处理从网站爬取的文件,该文件保存为带引号字段的分号csv格式。最后一个字段包含嵌入式换行符。我一直在编写处理该文件的脚本。我对perl还比较新,最初尝试使用普通的perl脚本,但很快发现那样行不通。我进行了研究并发现应该使用Text::CSV模块。我找到了这些网站,解释了如何使用该模块:

http://perlmaven.com/how-to-read-a-csv-file-using-perl

http://perlmeme.org/tutorials/parsing_csv.html

http://metacpan.org/pod/Text::CSV#Embedded-newlines

基本上我想要实现的是正确读取文件,使得所有字段能够被正确地分隔,而不是在换行符处断开。然后将该字段中的换行符删除,并将其写入新文件。
以下是原始数据示例:
 "2030";"NH Amersfoort";"Stationsstraat 75";"3811 MH AMERSFOORT";"033-4221200";"www.nh-hotels.nl";"52.154316";"5.380036";"<UL class=stars><LI>
 <LI>
 <LI>
 <LI></LI></UL>"
 "2031";"NH Amsterdam Centre";"Stadhouderskade 7";"1054 ES AMSTERDAM";"020-6851351";"www.nh-hotels.com";"52.363075";"4.879458";"<UL class=stars><LI>
 <LI>
 <LI>
 <LI></LI></UL>"
 "2032";"NH Atlanta Rotterdam Hotel";"Aert van Nesstraat 4";"3012 CA ROTTERDAM";"010-2067800";"www.nh-hotels.com";"51.921028";"4.478619";"<UL class=stars><LI>
 <LI>
 <LI>
 <LI></LI></UL>" 

而我想要的是这个:

 "2030";"NH Amersfoort";"Stationsstraat 75";"3811 MH AMERSFOORT";"033-4221200";"www.nh-hotels.nl";"52.154316";"5.380036";"<UL class=stars><LI><LI><LI><LI></LI></UL>"
 "2031";"NH Amsterdam Centre";"Stadhouderskade 7";"1054 ES AMSTERDAM";"020-6851351";"www.nh-hotels.com";"52.363075";"4.879458";"<UL class=stars><LI><LI><LI><LI></LI></UL>"
 "2032";"NH Atlanta Rotterdam Hotel";"Aert van Nesstraat 4";"3012 CA ROTTERDAM";"010-2067800";"www.nh-hotels.com";"51.921028";"4.478619";"<UL class=stars><LI><LI><LI><LI></LI></UL>" 

这是我的完整脚本。我已经尝试了10种不同的选项和建议,但它们都没有起作用!

 use strict;
 use warnings;    
 use Text::CSV;

 my $inputfile  = shift || die "Give input and output names!\n";
 my $outputfile = shift || die "Give output name!\n";

 open my $infile,  '<', $inputfile   or die "Sourcefile in use / not found :$!\n";
 open my $outfile, '>', $outputfile  or die "Outputfile in use :$!\n";

    my $csv = Text::CSV->new ({
binary => 1,
sep_char => ';'
});

while (my $elements = $csv->getline( $infile )) {
        my $stars = $elements->[8];
        #$ster =~ s/[\r\n]//g
        print "$stars\n\n";
        }

 close $infile;
 close $outfile;

这将正确地打印带有换行符的字段,但并没有将它们移除。我该如何做?使用正则表达式替换换行符不起作用。下一个问题是,当我弄清楚如何清理该字段时,我该如何打印新文件?

1
你是在问如何从字符串中删除一个字符以及如何将内容打印到文件吗?你应该知道,“不起作用”是描述问题的一种非常糟糕的方式。 - TLP
@TLP 真的!我尝试了很多不同的脚本,似乎把它们全部发布出来会过度了.. 是的,我正在询问如何从最后一个元素中删除CRLF。我知道如何做所有这些,但我不熟悉模块。我将编辑我的帖子以展示我尝试过什么。 - Jan
嗯,在你的代码中,你试图对变量 $ster 进行替换操作... 除非那是一个打字错误,否则你的问题就在那里。 - TLP
1个回答

2

我不确定你在这里问的是什么,因为看起来你已经得到了答案。然而,这段代码确实有效:

use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new ({
    binary => 1,
    sep_char => ';',
    eol => $/,                # to make $csv->print use newlines
    always_quote => 1,        # to keep your numbers quoted
});

while (my $row = $csv->getline( *DATA )) {
    $row->[8] =~ s/[\r\n]+//g;
    $csv->print(*STDOUT, $row);
}

__DATA__
"2030";"NH Amersfoort";"Stationsstraat 75";"3811 MH AMERSFOORT";"033-4221200";"www.nh-hotels.nl";"52.154316";"5.380036";"<UL class=stars><LI>
<LI>
<LI>
<LI></LI></UL>"
"2031";"NH Amsterdam Centre";"Stadhouderskade 7";"1054 ES AMSTERDAM";"020-6851351";"www.nh-hotels.com";"52.363075";"4.879458";"<UL class=stars><LI>
<LI>
<LI>
<LI></LI></UL>"
"2032";"NH Atlanta Rotterdam Hotel";"Aert van Nesstraat 4";"3012 CA ROTTERDAM";"010-2067800";"www.nh-hotels.com";"51.921028";"4.478619";"<UL class=stars><LI>
<LI>
<LI>
<LI></LI></UL>"

指针:

使用 Text::CSV 的打印功能时,通过设置 eol 选项可以达到预期效果,即打印出新行。我将 STDOUT 用作输出句柄,但您可以使用任何文件句柄。

我不知道为什么您说替换对您“无效”,但我怀疑可能是您做了类似这样的事情:

my $foo = $row->[8];
$foo =~ s/[\r\n]//g;
print @$row;

这不会改变$row中的值,只会改变$foo中的复制品。

哇,谢谢!经过一些摆弄,我终于让它运行起来了。你是正确的,我正在尝试你在最后一个例子中描述的方式...现在我明白为什么它不起作用了!我想我只是不知道如何与模块一起打印,因为它的工作方式与我习惯的方式不同。我也不太熟悉eol函数! - Jan
不客气。Text::CSV是一个很好的小模块,但它可能有点棘手。 - TLP
我已经让大部分工作正常运行了,但我可以问你最后一个问题吗?是否有可能在输出文件中删除所有引号?我需要引号以便模块可以正确处理带有换行符的元素,但我不再需要它们出现在输出文件中。我能使用一个替换来删除它们吗? - Jan
@Nickname27 不,引号不在 $row 数组中,当你打印时,它们是由 csv 模块添加的。当你开启 always_quote 时,该模块会为你处理引号,否则只在必要时才添加。请参考文档。 - TLP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接