我正在学习 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";
}
Run Code Online (Sandbox Code Playgroud)
文本文件输出:
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
欢迎任何好的反馈!
这里的关键部分是如何操作您的数据,以便提取每行需要打印的内容。那么你最好使用一个模块来生成有效的 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} ]);
}
Run Code Online (Sandbox Code Playgroud)
使用 hashref切片 按所需顺序从 hashrefs 中提取@{$href}{@hdr}值,一般情况下
@{ 表达式返回哈希引用 } { 键列表 }
这将从块中的表达式{}必须返回的 hashref 返回给定键列表的值列表。然后使用它来构建一个 arrayref(这里是一个匿名数组,使用[]),模块的say方法需要什么才能从该值列表中生成和打印逗号分隔值†的字符串。
请注意评估为哈希引用的块,而不是用于哈希切片的哈希名称。这是一个普遍的规则是
在您将标识符(或标识符链)作为变量或子例程名称的一部分放置的任何地方,您都可以用返回正确类型引用的 BLOCK 替换标识符。
一些进一步的评论
查看支持的构造函数的属性;有很多好东西
对于非常简单的数据,您可以简单地用逗号连接字段并打印
say $ofh join ',', @{$href}{@hdr};
Run Code Online (Sandbox Code Playgroud)
但是使用模块来构建有效的 CSV 记录要安全得多。通过在构造函数中正确选择属性,它可以处理嵌入到字段中的任何合法内容(其中一些可能需要相当多的工作才能手动正确完成)并且它调用不属于
我明确列出了列名。取而代之的是,您可以按照所需的顺序获取keys和 然后sort,但这将再次需要一个硬编码的列表进行排序
该程序创建该文件test.csv并将预期的标题和数据行打印到该文件中。
†但是,用逗号分隔这些“值”可能涉及的不仅仅是“CSV格式”的首字母缩略词所代表的含义。这些逗号之间可能会有很多东西,包括逗号、换行符等等。这就是为什么最好建议始终使用库的原因。查看构造函数的选项是有用的。
以下评论提到了最初的问题。同时,在 OP 的代码中更正了这个地址的问题,并更新了问题。我仍然会留下这些文本,以便进行一些可能有用的一般性评论。
至于问题中的代码及其输出,根据输出@data中键 的存在来判断,数据的处理方式几乎肯定存在问题HASH(address)。
HASH(0x...)当打印一个作为散列引用的变量(不能显示任何散列的内容)时,会输出该字符串。Perl 通过以这种方式对引用进行字符串化(从更复杂的东西中产生可打印的字符串)来处理这样的打印。
没有充分的理由为散列键提供散列引用。所以我建议你检查你的数据及其处理,看看它是如何发生的。(或者简单地展示这个,或者如果将它添加到这个问题中不可行,则发布另一个问题。)
您可以用来绕过的一种措施是仅使用您知道有效的密钥列表,如我上面所示;但是,那么您可能会留下一些未处理的彻底错误。所以我宁愿建议找出问题所在。