【问题标题】:In Perl, how can I parse a CSV file where the fields contain comma separated values? [closed]在 Perl 中,如何解析字段包含逗号分隔值的 CSV 文件? [关闭]
【发布时间】:2015-07-04 04:01:57
【问题描述】:

有一个名为file.csvcsv 文件,如下所示:(这只是一个示例)

"Name","Alias","Phone","email","address"
"rob","rob","534235","rob@example.com","US,UK"
"nik","nik","976784","nik@example.com,nik@foram.org","UK"
"picy","pic","327654,823747","pic@example.com","US"

在这个文件中有 5 个标题,但少数标题的值更多。任何标题都可以有任意数量的值意味着超过 2 或 3。

我试图得到这样的输出:

Name    Nickname    Phone        email                          address
rob     rob         534235       rob@example.com                US,UK
nik     nik         976784       nik@example.com,nik@foram.org  UK
picy    pic         327654,823747   pic@example.com             US

或任何特定列,但该列的数据将如上所示。

我知道splitspliting中的功能和限制:

while (<$fh>)
{
    my @data = split /,/, $_, 5;
}

但这在这里不起作用。

我怎样才能做到这一点?有什么想法吗?

【问题讨论】:

  • Split 不够聪明,无法在这里做你想做的事。例如,您至少需要一个简单的解析器来确定一个字段是电话还是电子邮件。首先,您需要能够定义语法并确定值是哪种类型的字段 - 例如,看起来 123455 将是电话号码 - 因此正则表达式 \d{6} 将仅匹配电话号码。您还可以为电子邮件地址定义一个正则表达式,但名称/昵称的区别会更难。见some parsers on cpan
  • 从 CPAN 下载 Text::CSV 或 Text::CSV_XS 并使用它。
  • @SinanÜnür:那么它不是 CSV 文件。 CPAN 背后的理念是其他人已经编写、调试并保存了他们的工作供您使用。不使用 CPAN 的模块意味着您正在重新发明轮子,这既昂贵又容易出错。
  • 我投票决定将此问题作为离题结束,因为 OP 不断更改数据,从而使提议的解决方案无效。
  • @SinanÜnür:这就是我的观点:验证和拒绝输入。 “问题”往往不是问题而是无效输入。

标签: perl csv split


【解决方案1】:

有了更新的信息,您的问题的解决方案现在很简单:

#!/usr/bin/env perl

use strict;
use warnings;

use Text::CSV_XS;
use Text::Table::Tiny;

my $csv = Text::CSV_XS->new;

my @data = ( $csv->getline(\*DATA) ); #header

while (my $row = $csv->getline(\*DATA)) {
    next unless @$row == @{ $data[0] };
    push @data, $row;
}

print Text::Table::Tiny::table(
    rows => \@data,
    header_row => 1,
);

__DATA__
"Name","Alias","Phone","email","address"
"rob","rob","534235","rob@example.com","US,UK"
"nik","nik","976784","nik@example.com,nik@foram.org","UK"
"picy","pic","327654,823747","pic@example.com","US"

输出:

+------+-------+---------------+--------------- ----------------+----------+
|姓名 |别名 |电话 |电子邮件 |地址 |
+--------+-------+----------------+------------------ -------------+----------+
|抢劫 |抢劫 | 534235 |抢@example.com |美国、英国 |
|尼克|尼克| 976784 | nik@example.com,nik@foram.org |英国 |
|辣的 |图片 | 327654,823747 | pic@example.com |美国 |
+--------+-------+----------------+------------------ ----------+---------+

您还可以通过使用 CSV 解析器解析每一行以及每一行中的字段来创建嵌套数据结构:

while (my $row = $csv->getline(\*DATA)) {
    next unless @$row == @{ $data[0] };
    push @data, [
        map [ $csv->parse($_) ? $csv->fields : () ], @$row
    ];
}

如果您的主要兴趣是处理数据,而不仅仅是打印出来,这将非常有用。

【讨论】:

  • 非常感谢。我还通过使用Text::CSV 模块解决了这个问题。但感谢您讲述创建嵌套数据结构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 2016-06-22
  • 2013-06-03
  • 1970-01-01
  • 2010-11-29
  • 2021-06-16
相关资源
最近更新 更多