无包Perl解析
我有一个csv文件,其中包含我想要解析并存储到某个数据结构中以打印到屏幕上的数据。我没有安装任何未预装的软件包或模块的选项。我熟悉CSV文本模式,但无法使用它,因此我必须手动执行此操作 数据如下所示:无包Perl解析,perl,Perl,我有一个csv文件,其中包含我想要解析并存储到某个数据结构中以打印到屏幕上的数据。我没有安装任何未预装的软件包或模块的选项。我熟悉CSV文本模式,但无法使用它,因此我必须手动执行此操作 数据如下所示: Name,Age,Weight,Target April, 23, 134, 90 Jenna, 45, 156, 90 Matt, 12, 90, 90 Aaron, 34, 190, 90
Name,Age,Weight,Target
April, 23, 134, 90
Jenna, 45, 156, 90
Matt, 12, 90, 90
Aaron, 34, 190, 90
Daniel, 22, 188, 90
到目前为止,我已经知道了,但它只是将所有数据存储到一个数组中并打印出来
use strict;
use warnings;
use Data::Dumper;
my $file = "file.csv";
my %people;
my @data;
open my $fh, $file or die "Could not open $file: $!";
while (my $line = <$fh>) {
chomp $line;
my @fields = split(/,/, $line);
push @data, @fields;
}
close $fh;
print join(", ", @data);
间距是由于csv列被隔开。标题行没有空格。我想要一种更有条理的方式来存储每个列的值,然后在屏幕上打印出来。如果您只需要在屏幕上进行冷打印,并且文件中的字段相同,请尝试以下方法:
#!/usr/bin/perl
use strict;
use warnings;
open(CSV, "< file.csv") or die "Can't open input file!\n";
my ($name, $age, $weight, $target);
format STDOUT =
@<<<<<<<<<@<<<<<<<<<@<<<<<<<<<@<<<<<<<<<
$name, $age, $weight, $target
.
while ( my $line = <CSV> ) {
chomp($line);
($name, $age, $weight, $target) = split(/,\s*/, $line);
write;
}
close(CSV);
如果您只需要在屏幕上进行冷打印,并且文件中的字段相同,请尝试以下方法:
#!/usr/bin/perl
use strict;
use warnings;
open(CSV, "< file.csv") or die "Can't open input file!\n";
my ($name, $age, $weight, $target);
format STDOUT =
@<<<<<<<<<@<<<<<<<<<@<<<<<<<<<@<<<<<<<<<
$name, $age, $weight, $target
.
while ( my $line = <CSV> ) {
chomp($line);
($name, $age, $weight, $target) = split(/,\s*/, $line);
write;
}
close(CSV);
我的工作是非常严格的使用任何不是预先安装的
好吧。关于这一点可以说很多,其中一些在评论中提到。但我现在就不谈了,因为这个问题非常明确
如果您的数据总是如图所示,那么事情就简单了。但我建议也添加代码来检查数据中的小精灵,这将摆脱手动解析;预处理的各种检查。这样你就会得到警告
话虽如此,在另一个答案中使用了很好的格式,我想对代码进行评论
问题是这条线
push @data, @fields;
将@fields
计算为其元素列表,然后将这些元素添加到数组中--它不会以某种方式将数组@fields
作为单个实体进行“添加”,我认为这是您所期望的。因此,当它不断地通过行时,它会不断地构建looong数组,所有数据都在一个长的平面列表中
相反,添加对@fields
数组的引用
while (my $line = <$fh>) {
chomp $line;
my @fields = split /\s*,\s*/, $line;
push @data, \@fields;
}
或者,对于@data
的所有元素,您将得到相同的引用
现在,@data
的元素是对行的引用,可以单独处理。比如说
use List::Util qw(max);
my $max_name_wt = max map { length $_->[0] } @data;
printf "%${max_name_wt}s %6s %6s %6s\n", @{ shift @data }; # headers
foreach my $row (@data) {
printf "%${max_name_wt}s %6d %6d %6d\n", @$row;
}
这假设数字都是整数,最多6位。它还假设没有字段丢失,或者它们的undef
将在printf
中显示警告。这是一个核心模块
有更简单的方法来打印复杂的数据结构;见核心
我的工作是非常严格的使用任何不是预先安装的
好吧。关于这一点可以说很多,其中一些在评论中提到。但我现在就不谈了,因为这个问题非常明确
如果您的数据总是如图所示,那么事情就简单了。但我建议也添加代码来检查数据中的小精灵,这将摆脱手动解析;预处理的各种检查。这样你就会得到警告
话虽如此,在另一个答案中使用了很好的格式,我想对代码进行评论
问题是这条线
push @data, @fields;
将@fields
计算为其元素列表,然后将这些元素添加到数组中--它不会以某种方式将数组@fields
作为单个实体进行“添加”,我认为这是您所期望的。因此,当它不断地通过行时,它会不断地构建looong数组,所有数据都在一个长的平面列表中
相反,添加对@fields
数组的引用
while (my $line = <$fh>) {
chomp $line;
my @fields = split /\s*,\s*/, $line;
push @data, \@fields;
}
或者,对于@data
的所有元素,您将得到相同的引用
现在,@data
的元素是对行的引用,可以单独处理。比如说
use List::Util qw(max);
my $max_name_wt = max map { length $_->[0] } @data;
printf "%${max_name_wt}s %6s %6s %6s\n", @{ shift @data }; # headers
foreach my $row (@data) {
printf "%${max_name_wt}s %6d %6d %6d\n", @$row;
}
这假设数字都是整数,最多6位。它还假设没有字段丢失,或者它们的undef
将在printf
中显示警告。这是一个核心模块
有更简单的方法来打印复杂的数据结构;请参阅核心。OP对复杂的数据结构没有充分的理解 请参阅下面用数据填充哈希的代码。这些数据可以用任何可以想象的方式进行处理
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $debug = 1; # debug flag
my %people; # store people's data
while(<DATA>){
next if /^\s*$/; # skip empty lines
next if /Name\,Age/; # skip header
s/\s+//g; # remove spaces
my @data = split ','; # obtain data
my %param; # temp hash
@param{qw/age weight target/} = @data[1..3];
$people{$data[0]} = \%param; # store param hash reference
}
say Dumper(\%people) if $debug;
$~ = 'STDOUT_HEADER';
write;
$~ = 'STDOUT';
my($person,$data);
while( ($person,$data) = each %people ) {
write;
}
$~ = 'STDOUT_FOOTER';
write;
format STDOUT_HEADER =
+--------------+-----+--------+--------+
| Name | Age | Weight | Target |
+--------------+-----+--------+--------+
.
format STDOUT =
| @<<<<<<<<<<< | @>> | @>>> | @>> |
$person, $data->{age}, $data->{weight}, $data->{target}
.
format STDOUT_FOOTER =
+--------------+-----+--------+--------+
.
__DATA__
Name,Age,Weight,Target
April, 23, 134, 90
Jenna, 45, 156, 90
Matt, 12, 90, 90
Aaron, 34, 190, 90
Daniel, 22, 188, 90
OP不能完全理解复杂的数据结构 请参阅下面用数据填充哈希的代码。这些数据可以用任何可以想象的方式进行处理
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $debug = 1; # debug flag
my %people; # store people's data
while(<DATA>){
next if /^\s*$/; # skip empty lines
next if /Name\,Age/; # skip header
s/\s+//g; # remove spaces
my @data = split ','; # obtain data
my %param; # temp hash
@param{qw/age weight target/} = @data[1..3];
$people{$data[0]} = \%param; # store param hash reference
}
say Dumper(\%people) if $debug;
$~ = 'STDOUT_HEADER';
write;
$~ = 'STDOUT';
my($person,$data);
while( ($person,$data) = each %people ) {
write;
}
$~ = 'STDOUT_FOOTER';
write;
format STDOUT_HEADER =
+--------------+-----+--------+--------+
| Name | Age | Weight | Target |
+--------------+-----+--------+--------+
.
format STDOUT =
| @<<<<<<<<<<< | @>> | @>>> | @>> |
$person, $data->{age}, $data->{weight}, $data->{target}
.
format STDOUT_FOOTER =
+--------------+-----+--------+--------+
.
__DATA__
Name,Age,Weight,Target
April, 23, 134, 90
Jenna, 45, 156, 90
Matt, 12, 90, 90
Aaron, 34, 190, 90
Daniel, 22, 188, 90
您可以将Text::CSV安装到,使用将其与应用程序捆绑在一起,或使用将Text::CSV\u PP打包到脚本中。@grinz我的工作对使用任何未预安装的内容都非常严格。因此,它在我当前的系统上不起作用。那么,我希望您知道,在解析由该模块处理的CSV时会出现多少复杂情况。可以通过使用和拆分模式
/\s*,\s*/
来解决眼前的问题,该模式将删除逗号周围的所有非有效空格。如果您有任何带引号的字段,例如包含逗号、空格或引号的字段,事情会变得更加复杂。Re“我的工作对使用任何未预装的内容都非常严格”,那么如何在计算机上获取脚本?为什么我们在CPAN上未测试的代码比在CPAN上测试的代码好?您可以将Text::CSV安装到一个,使用将其与应用程序捆绑在一起,或者使用将Text::CSV_PP打包到脚本中。@Grinnz我的工作对使用任何未预安装的东西都非常严格。因此,它在我当前的系统上不起作用。那么,我希望您知道,在解析由该模块处理的CSV时会出现多少复杂情况。可以通过使用和拆分模式/\s*,\s*/
来解决眼前的问题,该模式将删除逗号周围的所有非有效空格。如果您有任何带引号的字段,例如包含逗号、空格或引号的字段,事情会变得更加复杂。Re“我的工作对使用任何未预装的内容都非常严格”,那么如何在计算机上获取脚本?为什么我们在CPAN上未测试的代码比在CPAN上测试的代码好?