Tôi có thể sử dụng Text :: CSV_XS để phân tích chuỗi định dạng csv mà không ghi nó vào đĩa không?


8

Tôi đang nhận được "tệp csv" từ nhà cung cấp (sử dụng API của họ), nhưng những gì họ làm chỉ là đưa toàn bộ nội dung vào phản hồi của họ. Tất nhiên, đó sẽ không phải là một vấn đề quan trọng ngoại trừ việc một số người phiền phức đã nhập dữ liệu và đưa vào "các tính năng" như ngắt dòng. Những gì tôi đang làm bây giờ là tạo một tệp cho dữ liệu thô và sau đó mở lại để đọc dữ liệu:

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) ) { ...

Bằng cách nào đó, điều này có vẻ ... không phù hợp. Có vẻ như tôi chỉ có thể đọc dữ liệu từ nội dung $ answer-> (chuỗi đa dòng) như thể nó là một tệp. Nhưng tôi đang vẽ một khoảng trống hoàn toàn về cách làm điều này. Một con trỏ sẽ được đánh giá rất cao. Cảm ơn, Paul

Câu trả lời:


6

Bạn có thể sử dụng một tập tin chuỗi:

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) ) { ... }

3
Đây là một trong những thủ thuật yêu thích của tôi trong Perl và tôi viết khá nhiều về nó trong Lập trình Perl hiệu quả . Đối xử với nhiều thứ như một filehandle có nghĩa là bạn có một giao diện dễ dàng và quen thuộc hơn. Nó cũng đi theo một cách khác; bạn có thể ghi vào filehandle nhưng để nó hiển thị trong một chuỗi.
brian d foy

3
Vâng, thật tuyệt, tôi cũng sử dụng điều đó - người ta không nên quên rằng đó không phải là một tập tin thích hợp, để không gặp rắc rối; xem bài này chẳng hạn.
zdim

1
Vậy, cám ơn! Đó chính xác là những gì tôi đang tìm kiếm nhưng không hoàn toàn nhận được. Tôi không còn có thể nhớ chính xác những kết hợp nào tôi đã thử, nhưng rõ ràng tôi đã đóng nhưng không nhận được cú pháp hoàn toàn đúng.
Paul RN

5

Có, bạn có thể sử dụng Text :: CSV_XS trên một chuỗi, thông qua giao diện chức năng của nó

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;    

Lưu ý rằng điều này thực sự cần Text::CSV_XS(thông thường Text :: CSV hoạt động nhưng không phải với điều này).

Tôi không biết tại sao điều này không có sẵn trong giao diện OO (hoặc có lẽ là nhưng không được ghi lại).


Trong khi các phân tích trên phân tích chuỗi trực tiếp như đã hỏi, người ta cũng có thể giảm bớt khía cạnh "không liên quan" trong ví dụ của bạn bằng cách viết nội dung trực tiếp vào một tệp khi nó có được, hầu hết các thư viện hỗ trợ như thế nào với :content_filetùy chọn trong LWP :: UserAgent :: get phương thức .

Tôi cũng lưu ý rằng hầu hết thời gian bạn muốn thư viện giải mã nội dung, vì vậy LWP::UAđể sử dụng decoded_content(xem HTTP :: Feedback ).


3

Tôi đã đưa ra ví dụ này với Mojo :: UserAgent . Đối với đầu vào CSV, tôi đã sử dụng các bộ dữ liệu khác nhau từ Dữ liệu mở NYC . Điều này cũng sẽ xuất hiện trong bản cập nhật tiếp theo cho Mojo Web Client .

Tôi xây dựng yêu cầu mà không thực hiện yêu cầu ngay lập tức và điều đó mang lại cho tôi đối tượng giao dịch , $tx. Sau đó tôi có thể thay thế readsự kiện để tôi có thể gửi ngay các dòng vào 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);

Điều đó không tốt như tôi mong muốn vì tất cả dữ liệu vẫn hiển thị trong bộ đệm. Điều này hơi hấp dẫn hơn, nhưng nó dễ vỡ theo những cách tôi ghi chú trong các bình luận. Hiện tại tôi quá lười biếng để làm cho nó trở nên tốt hơn bởi vì nó sẽ nhanh chóng có lông khi bạn tìm ra khi bạn có đủ dữ liệu để xử lý một bản ghi. Mã cụ thể của tôi không quan trọng bằng ý tưởng rằng bạn có thể làm bất cứ điều gì bạn muốn khi giao dịch viên đọc dữ liệu và chuyển nó vào trình xử lý nội dung:

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];
            }
        };
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.