如何使用 Perl 将文本文件解析为 csv 文件

Beb*_*ebe 2 csv perl

我正在学习 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)

欢迎任何好的反馈!

zdi*_*dim 7

这里的关键部分是如何操作您的数据,以便提取每行需要打印的内容。那么你最好使用一个模块来生成有效的 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 通过以这种方式对引用进行字符串化(从更复杂的东西中产生可打印的字符串)来处理这样的打印。

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

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