【问题标题】:Removing extra commas from csv file in perl从 perl 中的 csv 文件中删除多余的逗号
【发布时间】:2018-05-12 15:59:31
【问题描述】:

我有多个 CSV 文件,每个文件都有不同数量的条目,每个大约有 300 行。

每个文件的第一行是数据标签

Person_id, person_name, person_email, person_address, person_recruitmentID, person_comments... etc

每个文件中的其余行包含数据

"0001", "bailey", "123 fake, street", "bailey@mail.com", "0001", "this guy doesnt know how to get rid of, commas!"... etc

我想去掉引号之间的逗号。 我目前正在浏览 Text::CSV 文档,但过程缓慢。

【问题讨论】:

  • 为什么?这听起来很像您认为它们会干扰 CSV 解析过程,但只要它们在带引号的字符串内,它们就不会引起问题,除非您尝试使用简单的“逗号分割”解析技术。我闻到了XY Problem。告诉我们您为什么要这样做。
  • 是的,我用逗号分割,在解析数据后,每一行都被放入一个散列中,其中键是第一行的数据,值是每隔一行的相应数据。 " hash = ( person_id => '0001', person_name =>"bailey" etc...)
  • 你已经有了一个非常棒的 CSV 解析器包,它将处理成功解析 CSV 的所有细节,包括处理包含逗号的引号字符串。你为什么不使用它?你所做的类似于得到一只火鸡和一套漂亮的锋利雕刻套装,但决定用大锤砸火鸡并徒手摘下肉。
  • 我不知道如何使用 CSV 解析器,我仍在阅读文档,我知道它可以用正则表达式完成,但我不太了解正则表达式。我不想打碎我的火鸡。

标签: perl csv


【解决方案1】:

一个好的 CSV 解析器不会有这个问题,因为逗号在引用的字段内,所以你可以简单地用它来解析文件。

一个非常好的模块是Text::CSV_XS,当你使用包装器Text::CSV时默认加载它。数据中唯一需要解决的是字段之间的空格,因为它们不在 CSV 规范中,所以我在下面的示例中使用了该选项。

如果您确实必须删除逗号以进行进一步的工作,请在解析器交给您行时执行此操作。

use warnings;
use strict;
use feature 'say';

use Text::CSV;

my $file = 'commas_in_fields.csv';

my $csv = Text::CSV->new( { binary => 1, allow_whitespace => 1 } ) 
    or die "Cannot use CSV: " . Text::CSV->error_diag (); 

open my $fh, '<', $file or die "Can't open $file: $!";

my @headers = @{ $csv->getline($fh) };   # if there is a separate header line

while (my $line = $csv->getline($fh)) {  # returns arrayref
    tr/,//d for @$line;                  # delete commas from each field
    say "@$line";
}

为了简洁起见,这在for 循环中的$_ 上使用tr,更改数组的元素。


我想重复并强调其他人的解释:不要手动解析 CSV,因为只有麻烦等待;使用图书馆。这非常类似于解析 XML 和类似格式:请不要使用正则表达式,而是使用库。

【讨论】:

    【解决方案2】:

    让我们解决这个问题:您无法通过逗号分隔来读取 CSV。您刚刚证明了原因;逗号可能被转义或在引号内。这些逗号是完全有效的,它们是数据的一部分。丢弃它们会破坏 CSV 中的数据。

    出于这个原因以及其他原因,必须使用 CSV 解析库来读取 CSV 文件。要查找哪些逗号是数据,哪些逗号是结构性的,还需要使用 CSV 解析库解析 CSV。因此,您不会通过尝试从引号内删除逗号来节省任何时间。相反,您将在处理数据时给自己更多的工作。您必须使用 CSV 解析库。

    Text::CSV_XS 是一个非常好的、非常快速的 CSV 解析库。它有很多功能,其中大部分是你不需要的。幸好it has examples for doing most common actions

    例如,以下是您从名为file.csv 的文件中读取和打印每一行的方法。

    use strict;
    use warnings;
    use autodie;
    use v5.10;   # for `say`
    
    use Text::CSV_XS;
    
    # Open the file.
    open my $fh, "<", "file.csv";
    
    # Create a new Text::CSV_XS object.
    # allow_whitespace allows there to be whitespace between the fields
    my $csv = Text::CSV_XS->new({
        allow_whitespace => 1
    });
    
    # Read in the header line so it's not counted as data.
    # Then you can use $csv->getline_hr() to read each row in as a hash.
    $csv->header($fh);
    
    # Read each row.
    while( my $row = $csv->getline($fh) ) {
        # Do whatever you want with the list of cells in $row.
        # This prints them separated by semicolons.
        say join "; ", @$row;
    }
    

    【讨论】:

    • 谢谢,好的,我不会尝试删除逗号
    猜你喜欢
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多