我可以使用 Text::CSV_XS 来解析 csv 格式的字符串而不将其写入磁盘吗?
Can I use Text::CSV_XS to parse a csv-format string without writing it to disk?
我从供应商那里得到了一个 "csv file"(使用他们的 API),但他们所做的只是把整个事情都吐到他们的回复中。当然,除了一些讨厌的人输入数据并像换行符一样输入 "features" 之外,这不会是一个重大问题。我现在正在做的是为原始数据创建一个文件,然后重新打开它来读取数据:
open RAW, ">", "$rawfile" or die "ERROR: Could not open $rawfile for write: $! \n";
print RAW $response->content;
close RAW;
my $csv = Text::CSV_XS->new({ binary=>1,always_quote=>1,eol=>$/ });
open my $fh, "<", "$rawfile" or die "ERROR: Could not open $rawfile for read: $! \n";
while ( $line = $csv->getline ($fh) ) { ...
不知何故,这似乎...不雅。看来我应该能够从 $response->content(多行字符串)中读取数据,就好像它是一个文件一样。但我对如何做到这一点一无所知。
一个指针将不胜感激。
谢谢,
保罗
您可以使用字符串文件句柄:
my $data = $response->content;
open my $fh, "<", $data or croak "unable to open string filehandle : $!";
my $csv = Text::CSV_XS->new({ binary=>1,always_quote=>1,eol=>$/ });
while ( $line = $csv->getline ($fh) ) { ... }
是的,您可以通过其功能接口在字符串上使用 Text::CSV_XS
use warnings;
use strict;
use feature 'say';
use Text::CSV_XS qw(csv); # must use _XS version
my $csv = qq(a,line\nand,another);
my $aoa = csv(in => $csv)
or die Text::CSV->error_diag;
say "@$_" for @aoa;
请注意,这确实需要 Text::CSV_XS
(通常 Text::CSV 有效,但不适用于此)。
我不知道为什么这在 OO 界面中不可用(或者可能是但没有记录)。
虽然上面直接按照要求解析字符串,但也可以通过在获取内容时将内容直接写入文件来减少示例中的 "inelegant" 方面,大多数库都支持 :content_file
LWP::UserAgent::get 方法中的选项。
我还要注意,大多数时候您希望图书馆解码内容,因此 LWP::UA
使用 decoded_content
(参见 HTTP::Response)。
我用 Mojo::UserAgent. For the CSV input I used various data sets from the NYC Open Data. This is also going to appear in the next update for Mojo Web Clients 编造了这个例子。
我没有立即发出请求就构建了请求,这给了我交易对象,$tx
。然后我可以替换 read
事件,这样我就可以立即将行发送到 Text::CSV_XS:
#!perl
use v5.10;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = ...;
my $tx = $ua->build_tx( GET => $url );
$tx->res->content->unsubscribe('read')->on(read => sub {
state $csv = do {
require Text::CSV_XS;
Text::CSV_XS->new;
};
state $buffer;
state $reader = do {
open my $r, '<:encoding(UTF-8)', $buffer;
$r;
};
my ($content, $bytes) = @_;
$buffer .= $bytes;
while (my $row = $csv->getline($reader) ) {
say join ':', $row->@[2,4];
}
});
$tx = $ua->start($tx);
这不像我希望的那样好,因为所有数据仍然显示在缓冲区中。这稍微更有吸引力,但就我在评论中提到的方式而言,它很脆弱。我现在太懒了,无法让它变得更好,因为当您确定何时有足够的数据来处理记录时,它会很快变得毛茸茸。我的特定代码并不重要,因为当事务处理程序读取数据并将其传递到内容处理程序时,您可以随心所欲地做任何事情:
use v5.10;
use strict;
use warnings;
use feature qw(signatures);
no warnings qw(experimental::signatures);
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = ...;
my $tx = $ua->build_tx( GET => $url );
$tx->res->content
->unsubscribe('read')
->on( read => process_bytes_factory() );
$tx = $ua->start($tx);
sub process_bytes_factory {
return sub ( $content, $bytes ) {
state $csv = do {
require Text::CSV_XS;
Text::CSV_XS->new( { decode_utf8 => 1 } );
};
state $buffer = '';
state $line_no = 0;
$buffer .= $bytes;
# fragile if the entire content does not end in a
# newline (or whatever the line ending is)
my $last_line_incomplete = $buffer !~ /\n\z/;
# will not work if the format allows embedded newlines
my @lines = split /\n/, $buffer;
$buffer = pop @lines if $last_line_incomplete;
foreach my $line ( @lines ) {
my $status = $csv->parse($line);
my @row = $csv->fields;
say join ':', $line_no++, @row[2,4];
}
};
}
我从供应商那里得到了一个 "csv file"(使用他们的 API),但他们所做的只是把整个事情都吐到他们的回复中。当然,除了一些讨厌的人输入数据并像换行符一样输入 "features" 之外,这不会是一个重大问题。我现在正在做的是为原始数据创建一个文件,然后重新打开它来读取数据:
open RAW, ">", "$rawfile" or die "ERROR: Could not open $rawfile for write: $! \n";
print RAW $response->content;
close RAW;
my $csv = Text::CSV_XS->new({ binary=>1,always_quote=>1,eol=>$/ });
open my $fh, "<", "$rawfile" or die "ERROR: Could not open $rawfile for read: $! \n";
while ( $line = $csv->getline ($fh) ) { ...
不知何故,这似乎...不雅。看来我应该能够从 $response->content(多行字符串)中读取数据,就好像它是一个文件一样。但我对如何做到这一点一无所知。 一个指针将不胜感激。 谢谢, 保罗
您可以使用字符串文件句柄:
my $data = $response->content;
open my $fh, "<", $data or croak "unable to open string filehandle : $!";
my $csv = Text::CSV_XS->new({ binary=>1,always_quote=>1,eol=>$/ });
while ( $line = $csv->getline ($fh) ) { ... }
是的,您可以通过其功能接口在字符串上使用 Text::CSV_XS
use warnings;
use strict;
use feature 'say';
use Text::CSV_XS qw(csv); # must use _XS version
my $csv = qq(a,line\nand,another);
my $aoa = csv(in => $csv)
or die Text::CSV->error_diag;
say "@$_" for @aoa;
请注意,这确实需要 Text::CSV_XS
(通常 Text::CSV 有效,但不适用于此)。
我不知道为什么这在 OO 界面中不可用(或者可能是但没有记录)。
虽然上面直接按照要求解析字符串,但也可以通过在获取内容时将内容直接写入文件来减少示例中的 "inelegant" 方面,大多数库都支持 :content_file
LWP::UserAgent::get 方法中的选项。
我还要注意,大多数时候您希望图书馆解码内容,因此 LWP::UA
使用 decoded_content
(参见 HTTP::Response)。
我用 Mojo::UserAgent. For the CSV input I used various data sets from the NYC Open Data. This is also going to appear in the next update for Mojo Web Clients 编造了这个例子。
我没有立即发出请求就构建了请求,这给了我交易对象,$tx
。然后我可以替换 read
事件,这样我就可以立即将行发送到 Text::CSV_XS:
#!perl
use v5.10;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = ...;
my $tx = $ua->build_tx( GET => $url );
$tx->res->content->unsubscribe('read')->on(read => sub {
state $csv = do {
require Text::CSV_XS;
Text::CSV_XS->new;
};
state $buffer;
state $reader = do {
open my $r, '<:encoding(UTF-8)', $buffer;
$r;
};
my ($content, $bytes) = @_;
$buffer .= $bytes;
while (my $row = $csv->getline($reader) ) {
say join ':', $row->@[2,4];
}
});
$tx = $ua->start($tx);
这不像我希望的那样好,因为所有数据仍然显示在缓冲区中。这稍微更有吸引力,但就我在评论中提到的方式而言,它很脆弱。我现在太懒了,无法让它变得更好,因为当您确定何时有足够的数据来处理记录时,它会很快变得毛茸茸。我的特定代码并不重要,因为当事务处理程序读取数据并将其传递到内容处理程序时,您可以随心所欲地做任何事情:
use v5.10;
use strict;
use warnings;
use feature qw(signatures);
no warnings qw(experimental::signatures);
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = ...;
my $tx = $ua->build_tx( GET => $url );
$tx->res->content
->unsubscribe('read')
->on( read => process_bytes_factory() );
$tx = $ua->start($tx);
sub process_bytes_factory {
return sub ( $content, $bytes ) {
state $csv = do {
require Text::CSV_XS;
Text::CSV_XS->new( { decode_utf8 => 1 } );
};
state $buffer = '';
state $line_no = 0;
$buffer .= $bytes;
# fragile if the entire content does not end in a
# newline (or whatever the line ending is)
my $last_line_incomplete = $buffer !~ /\n\z/;
# will not work if the format allows embedded newlines
my @lines = split /\n/, $buffer;
$buffer = pop @lines if $last_line_incomplete;
foreach my $line ( @lines ) {
my $status = $csv->parse($line);
my @row = $csv->fields;
say join ':', $line_no++, @row[2,4];
}
};
}