【问题标题】:How to parse a text file to csv file using Perl如何使用Perl解析为CSV文件的文本文件
【发布时间】:2021-02-28 07:04:04
【问题描述】:

我正在学习 Perl,并希望使用 Perl 将文本文件解析为 csv 文件。我有一个生成以下文本文件的循环:

//This part is what outputs on the text file
for $row(@$data) {
  while(my($key,$value) = each(%$row)) {
    print "${key}=${value}, ";
  }
  print "\n";
}

文本文件输出:

name=Mary, id=231, age=38, weight=130, height=5.05, speed=26.233, time=30, 
time=25, name=Jose, age=30, id=638, weight=150, height=6.05, speed=20.233, 
age=40, weight=130, name=Mark, id=369, speed=40.555, height=5.07, time=30 

CSV 文件所需的输出:

name,age,weight,height,speed,time
Mary,38,130,5.05,26.233,30, 
Jose,30,150,6.05,20.233,25, 
Mark,40,130,5.04,40.555,30

欢迎任何好的反馈!

【问题讨论】:

  • 是的,没有空格只是想在这篇文章中清楚地表明这一点。好的,改了!
  • 为了提供更多帮助,我们真的需要看到$data
  • 另外,这听起来不像是在解析 CSV 文件。您似乎正在创建一个 CSV 文件。
  • 我想从该文本文件创建一个 CSV 文件。数据是一个哈希数组,类似于 zdim 所做的。
  • @Bebe 太好了,我很高兴听到这个消息 :)。我删除了一些现在已经过时的早期 cmets(因为它们已通过编辑问题得到解决),以进行清理,以免它们分散注意力。由于我看到您实现了我对代码的最后评论,因此我编辑了您的问题以更正一些地方;请查看。

标签: csv perl


【解决方案1】:

这里的关键部分是如何操作您的数据,以便提取每行需要打印的内容。那么你最好使用一个模块来生成有效的 CSV,Text::CSV 非常好。

使用小哈希引用数组的程序,模仿问题中的数据

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

use Text::CSV;

my @data = ( 
    { name => 'A', age => 1, weight => 10 },
    { name => 'B', age => 2, weight => 20 },
);
    
my $csv = Text::CSV->new({ binary => 1, auto_diag => 2 });

my $outfile = 'test.csv';
open my $ofh, '>', $outfile or die "Can't open $outfile: $!";

# Header, also used below for order of values for fields 
my @hdr = qw(name age weight);
$csv->say($ofh, \@hdr);

foreach my $href (@data) {
    $csv->say($ofh, [ @{$href}{@hdr} ]); 
}

使用 hashref slice @{$href}{@hdr} 以所需顺序从 hashrefs 中提取值,一般情况下

@{ 表达式返回哈希引用 } { 键列表 }

这将返回给定键列表的值列表,来自块 {} 中的表达式必须返回的 hashref。然后使用它来构建一个 arrayref(这里是一个匿名数组,使用 []),模块的 say method 需要什么来制作和打印一个逗号分隔值字符串该值列表。

注意一个计算为散列引用的块,而不是用于 散列 切片的 散列名称。这是一般rule那个

在任何将标识符(或标识符链)作为变量或子例程名称的一部分放置的地方,都可以将标识符替换为返回正确类型引用的 BLOCK。

一些进一步的cmets

  • 查看支持的构造函数的属性;好东西很多

  • 对于非常简单的数据,您可以简单地用逗号连接字段并打印

    say $ofh join ',', @{$href}{@hdr};    
    

    但是使用模块来构建有效的 CSV 记录要安全得多。通过在构造函数中正确选择属性,它可以处理嵌入字段中的任何合法内容(其中一些可能需要相当多的工作才能手动正确完成)并且它调用的东西是' t

  • 我明确列出列名。相反,您可以按所需顺序获取keys,然后获取sort,但这将再次需要一个硬编码列表进行排序

程序创建文件test.csv 并向其打印预期的标题和数据行。


但是用逗号分隔这些“值”可能涉及的不仅仅是“CSV 格式”的首字母缩写词所代表的含义。这些逗号之间可能会出现各种各样的东西,包括逗号、换行符等等。这就是为什么最好建议始终使用库的原因。看到构造函数的选项是有用的。


以下评论提到了最初的问题。同时,在 OP 的代码中更正了这些地址的问题并更新了问题。我仍然将本文留给一些可能有用的通用 cmets。

至于问题中的代码及其输出,几乎可以肯定的是,如何处理数据以生成 @data 存在问题,通过 keys HASH(address) 在输出。

当打印一个作为哈希引用的变量时输出字符串HASH(0x...)(不能显示任何哈希内容)。 Perl 通过 stringifying 处理这样的打印(从更复杂的东西中生成可打印的字符串)以这种方式引用。

没有充分的理由为散列键提供散列引用。所以我建议你检查你的数据及其处理,看看它是如何产生的。 (或者简短地展示这个,或者如果将它添加到这个问题中不可行,则发布另一个问题。)

您可以用来绕过的一种措施是仅使用您知道有效的密钥列表,就像我在上面展示的那样;但是,那么您可能会留下一些未处理的彻底错误。所以我宁愿建议找出问题所在。

【讨论】:

  • 谢谢@zdim,是的,它应该是大写的哈希并添加了逗号,将尝试您的示例!
  • Text::CSV 是将文本文件解析为 csv 的唯一方法?我正在考虑编写一个 perl 脚本来获取该文本文件并用几行代码将其解析为 csv :)
  • @Bebe 我假设您以某种方式“解析”(处理)某些文件以获得@data。然后需要使用它来获取输出值(Mary38130,...等);为此,我使用@{$href}{@hdr}。一旦你有了它,你就可以将它打印到一个文件中,值之间用逗号分隔。为此,我使用(并建议)Text::CSV 来打印 CSV 样式的输出(CSV 代表 Comma-Separated-Values)。但是对于简单的数据,您可以手动完成(如评论中所示)
  • @Bebe 请参阅我编造的@data——这就是带有哈希引用的数组的外观。如果你在输出中有一个HASH(....) => ,这意味着有一个键本身就是一个哈希引用。我不知道为什么会这样,但几乎可以肯定这是某种错误。调查原始数据(在从中获取它的文件中)以及如何处理它以获取您的 @data(那么,如何“解析”该文件以从中构建 @data)。
  • @Bebe 感谢您澄清和编辑 hash(...) 的事情!我在答案的末尾添加了对此的评论
猜你喜欢
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多