perl - 当只需要字段的子集时,分割长行的高性能方法是什么

标签 perl csv text-parsing string-parsing

我的查询的详细信息如下:

  1. 我有一个非常大的 TSV(Tab Sep. Value)文件(其中大于 30 GB)。
  2. 我想从此文件中提取某些不以空最后字段结尾的行。由于这是一个 TSV 文件,因此那些不以 \t\n 结尾的行,这是一个简单的测试,不是这个问题的主题。这将立即删除大约 75% 的线路,从而减少工作量。
  3. 然后我想从剩余的行中提取一小部分字段。这些字段不连续,但数量很少(例如,总共三十多个字段中的七个)。例如,假设字段 2,3,12-18,25-28,31
  4. 我要提取的行非常长,大多数长达 1,000 个字符,因为它们包含大量制表符分隔字段。

显然,一个选择是使用以下简单的代码,我已尝试对其进行良好的格式化并包含注释以显示我的推理:

use warnings;
use strict;
# I am using the latest stable version of Perl for this exercise
use 5.30.0;

while (<>)
{
  # Skip lines ending with an empty field
  next if substr($_,-2) eq "\t\n";

  # Remove "\n"
  chomp;

  # Split matching lines into fields on "\t", creating @fields
  my @fields=split(/\t/,$_);

  # Copy only the desired fields from @fields to create a new
  # line in TSV format
  # This can be done in one simple step in Perl, using
  # array slices and the join() function
  my $new_line=join("\t",@fields[2,3,12..18,25..28,31]);

  # ...
}

但是,使用 split 会导致额外的解析(超出我需要的最后一个字段)并生成我也不需要的完整字段数组。我认为不创建数组会更有效,而是解析每一行以查找选项卡并计算字段索引,在途中创建输出行,并在我需要的最后一个字段处停止。

我的评估是否正确,或者只是进行简单的分割,然后对包含感兴趣字段的切片进行连接,这是最好的方法从性能角度来看?

更新:不幸的是,没有人提到使用GNU cut进行分割并将结果传输到Perl中进行其余处理的可能性。这可能是最高效的方法,无需编写大量自定义 (C) 代码来执行此操作,也无需借助自定义行解析(也在 C 中)进行基于大块的读取。

最佳答案

您可以使用其 limit 参数告诉 split 何时停止:

my @fields=split(/\t/,$_,33);

(指定比您实际需要的字段数多一个的字段,因为它生成的最后一个字段将包含该行的剩余部分。)

关于perl - 当只需要字段的子集时,分割长行的高性能方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56670693/

相关文章:

sqlite - 如何将内存中的sqlite数据库保存到perl中的文件中?

perl - 更新到 Windows 10 后 Net::SSH2::Simple 失败

Python dict 到列格式的 csv

java - 使用 OpenCSV 仅部分解析 CSV 文件

java - 如何解析Java Swing文本框中输入的磁条卡数据?

math - 计算一串简单的数学表达式

perl - 为什么我不应该在 UNIVERSAL 包中创建 AUTOLOAD 子例程?

Perl 死于 : "Usage: DBD::Pg::db::DESTROY(dbh) during global destruction"

mysql加载数据infile它包含比输入列更多的数据

php - 将数字数组和带连字符的数字范围扩展为整数数组