Perl中速度最快的CSV解析器

Car*_*e18 11 csv perl parsing

我正在创建一个子程序:

(1)解析CSV文件;

(2)并检查该文件中的所有行是否具有预期的列数.如果列数无效,则会出现问题.

如果行数从数千到数百万不等,您认为最有效的方法是什么?

现在,我正在尝试这些实现.

(1)基本文件解析器

open my $in_fh, '<', $file or 
    croak "Cannot open '$file': $OS_ERROR";                                                            

my $row_no = 0;                                                                                           
while ( my $row = <$in_fh> ) {                                                                            
    my @values = split (q{,}, $row);                                                                      
    ++$row_no;                                                                                            
    if ( scalar @values < $min_cols_no ) {                                                                
        croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
    }                                                                                                     
}                                                                                                         

close $in_fh                                                                                              
    or croak "Cannot close '$file': $OS_ERROR";                                                           
Run Code Online (Sandbox Code Playgroud)

(2)使用Text :: CSV_XS(bind_columns和csv-> getline)

my $csv = Text::CSV_XS->new () or                                                                         
   croak "Cannot use CSV: " . Text::CSV_XS->error_diag();                                                 
open my $in_fh, '<', $file or                                                                             
   croak "Cannot open '$file': $OS_ERROR";                                                                

 my $row_no = 1;                                                                                          
 my @cols = @{$csv->getline($in_fh)};                                                                     
 my $row = {};                                                                                            
 $csv->bind_columns (\@{$row}{@cols});                                                                    
 while ($csv->getline ($in_fh)) {                                                                         
    ++$row_no;                                                                                            
    if ( scalar keys %$row < $min_cols_no ) {                                                             
        croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
    }                                                                                                     
}                                                                                                         

$csv->eof or $csv->error_diag();                                                                          
close $in_fh or
    croak "Cannot close '$file': $OS_ERROR";                                                           
Run Code Online (Sandbox Code Playgroud)

(3)使用Text :: CSV_XS(csv-> parse)

my $csv = Text::CSV_XS->new() or                                                                         
   croak "Cannot use CSV: " . Text::CSV_XS->error_diag();                                                
 open my $in_fh, '<', $file or                                                                           
   croak "Cannot open '$file': $OS_ERROR";                                                               

 my $row_no = 0;                                                                                         
 while ( <$in_fh> ) {                                                                                    
     $csv->parse($_);                                                                                    
     ++$row_no;                                                                                          
     if ( scalar $csv->fields < $min_cols_no ) {                                                         
       croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
     }                                                                                                   
}                                                                                                        

$csv->eof or $csv->error_diag();                                                                         
close $in_fh or 
    croak "Cannot close '$file': $OS_ERROR";                                                          
Run Code Online (Sandbox Code Playgroud)

(4)使用Parse :: CSV

use Parse::CSV;                                                                                           
my $simple = Parse::CSV->new(                                                                             
    file => $file                                                                                         
);                                                                                                        

my $row_no = 0;                                                                                           
while ( my $array_ref = $simple->fetch ) {                                                                
    ++$row_no;                                                                                            
    if ( scalar @$array_ref < $min_cols_no ) {                                                            
        croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
    }                                                                                                     
}                                                                                                         
Run Code Online (Sandbox Code Playgroud)

我使用Benchmark模块对它们进行基准测试.

use Benchmark qw(timeit timestr timediff :hireswallclock);
Run Code Online (Sandbox Code Playgroud)

这些是我得到的数字(以秒为单位):

1000行文件:

实施1:0.0016

实施2:0.0025

实施3:0.0050

实施4:0.0097

10,000行文件:

实施1:0.0204

实施2:0.0244

实施3:0.0523

实施4:0.1050

1,500,000行文件:

实施1:1.8697

实施2:3.1913

实施3:7.8475

实施4:15.6274

鉴于这些数字,我会得出结论,简单的解析器是最快的,但从我从不同来源读取的,Text :: CSV_XS应该是最快的.

有人会对此赐教吗?我如何使用这些模块有什么问题吗?非常感谢你的帮助!

mob*_*mob 17

有CSV文件

header1,header2,header3
value1,value2,value3
Run Code Online (Sandbox Code Playgroud)

然后有CSV文件.

header1,"This, as they say, is header2","And header3
even contains a newline!"
value1,"value2, 2nd in a series of 3 values",value3
Run Code Online (Sandbox Code Playgroud)

Text::CSV和它的同类经过精心开发和测试,以处理第二种.如果您确信您的输入确实并且始终符合简单的CSV规范,那么很可能您可以构建一个性能优于其他的解析器Text::CSV.


dan*_*111 9

请注意,您的Text::CSV_XS版本比简单的解析器版本更多.它将行拆分,将其放入内存,并使hashref指向字段.

它也可能有其他逻辑,比如允许转义分隔符(我不知道,因为我没有使用它).最重要的是,在使用模块时总是会有少量开销:函数调用,来回传递参数,以及可能在您的情况下并不真正适用的通用代码(例如错误检查您要做的事情)关心).

通常,使用模块的好处大大超过了成本.您可以获得更多功能,更可靠的代码等.但是,对于一个小而简单的任务,这可能不是真的.如果您只需要验证列数,则使用模块可能会过度.您可以通过计算列数来更快地实现自己的实现,而不必费心去分割:

/(?:,[^,]*){$min_cols_no-1}/ or croak "Did not find minimum number of columns";
Run Code Online (Sandbox Code Playgroud)

如果您要在此验证步骤之外进行实际处理,则使用该模块可能会有所帮助.