【问题标题】:Can Perl's Text::CSV_XS be used to remove columns from CSVs?Perl 的 Text::CSV_XS 可以用来从 CSV 中删除列吗?
【发布时间】:2013-05-17 19:43:52
【问题描述】:

出于工作目的,我有几个 CSV 文件已被供应商升级修改,现在它们包含的列比以前多 80 列。不利的一面是,这些文件用于计费,因此我们需要修剪掉新列。好处是所有列都已添加到记录的末尾。较旧的记录包含 251 列。新记录包含 336 个。

所以,我正在编写的脚本将接受 CSV 文件名作为参数,在原地编辑它,因为文件可能非常大,删除前两行和最后一行,最后删除新列(不仅仅是清空它们的内容,完全删除它们,所以如果原始格式有N列,处理后的新格式应该只有N列)

这是我目前所拥有的:

use strict;
use warnings;

#Use Tie::File to modify file contents directly on disk, without reading
#to memory.
use Tie::File;

#Use Text::CSV_XS to quickly remove columns from CSV. External library
#used to compensate for quoted fields.
use Text::CSV_XS;

my $csvparser = Text::CSV_XS->new () or die "".Text::CSV_XS->error_diag();
my $file;

foreach $file (@ARGV){
        my @CSVFILE;
        my $csvparser = Text::CSV_XS->new () or die "".Text::CSV_XS->error_diag();
        tie @CSVFILE, 'Tie::File', $file or die $!;
        shift @CSVFILE;
        shift @CSVFILE;
        pop @CSVFILE;
        for my $line (@CSVFILE) {
                $csvparser->parse($line);
                my @fields = $csvparser->fields;
                splice @fields, -85;
                $line = $csvparser->combine(@fields);
        }

        untie @CSVFILE;
}

这将运行,并且第一部分运行正确(删除前 2 行和最后一行)。但是我不确定如何继续删除新列。我一直在阅读 Text::CSV_XS 的文档,但似乎找不到任何可以删除列的函数。一些例子可能会有所帮助,但我承认我的 perl 技能不是很好。我想要使​​用该模块的主要原因是这些 CSV 文件有时确实包含带逗号的字段,用引号括起来,模块可以处理。

任何关于如何解决这个问题的建议都会很棒。另外,如果我的方法有问题,请告诉我。我绝不是 perl 专家,并且愿意接受任何有用的批评,因为这将被输入计费系统。

编辑:将下面的建议包含在代码中。如下所述,运行此程序时,源文件的内容会在每一行替换为单个“1”。

【问题讨论】:

  • 不要对 Perl 局部变量使用大写字母。它们是为@ARGVText::CSV_XS 等全局名称保留的。
  • 我的印象是基于旧骆驼书的标准是文件句柄使用全部大写? docstore.mik.ua/orelly/perl/perlnut/ch04_09.htm那个风格变了吗??
  • 旧式文件句柄也是 global 的,所以全大写。当前的最佳实践是对文件句柄使用词法标量变量,因此现在是 open my $fh, '<', 'filename' 而不是 open FH, 'filename'

标签: perl csv


【解决方案1】:

是的,你可以按你的要求做,虽然我不希望有任何很快的速度。

这样的东西应该可以工作

use strict;
use warnings;

use Tie::File;
use Text::CSV_XS;

my $csv = Text::CSV_XS->new or die Text::CSV_XS->error_diag;

foreach my $file (@ARGV) {

    tie my @lines, 'Tie::File', $file or die $!;

    splice @lines, 0, 2;
    pop @lines;

    for my $line (@lines) {
        $csv->parse($line);
        my @fields = $csv->fields;
        splice @fields, -80;
        $csv->combine(@fields);
        $line = $csv->string;
    }

    untie @lines;
}

【讨论】:

  • 这是在正确的轨道上,但是在这样做之后文件充满了“1”。我已经用新代码更新了这个问题。感谢您迄今为止的帮助!
  • @Matthew:对不起,我的 IDE 和这篇文章之间似乎有一个伤亡。缺少一行代码。现在应该可以正常工作了。
  • 与其删除尾随的 80 列,我更希望这段代码保留特定数量的列。但是,您不知道删除不需要的 80 后应该剩下多少。大概您知道,因此您可以将 -80 替换为该数字。
  • 最终目标是只有 251 列,如前所述,供应商升级增加了 85 列,使新的总数为 336。我们的计费系统设置为处理该数量的字段,但遇到了问题与已添加的新的。
  • 嗯好的,那你要splice @fields, 251
猜你喜欢
  • 1970-01-01
  • 2018-10-29
  • 2019-05-17
  • 2013-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
  • 1970-01-01
相关资源
最近更新 更多