对Perl来说很新,需要你的帮助
我有一个CSV文件xyz.csv
,内容为:
这里的level1和er值是字符串名称......不是数字......
level1,er
level2,er2
level3,er3
level4,er4
我使用下面的脚本解析此CSV文件,并在第一次运行中将字段传递给数组
open(my $d, '<', $file) or die "Could not open '$file' $!\n";
while (my $line = <$d>) {
chomp $line;
my @data = split "," , $line;
@XYX = ( [ "$data[0]", "$data[1]" ], );
}
对于第二次运行,我从命令提示符处获取输入并存储在变量$val
中。我的程序应该从存储在变量中的值解析CSV文件,直到它到达文件的末尾
例如
我输入level2
所以我需要一个脚本从第二行解析到CSV文件的末尾,忽略文件中level2
之前的值,然后传递这些值({{1 } level2
}到level4
@XYX = (["$data[1]","$data[1]"],);}
我输入level2,er2
level3,er3
level4,er4
所以我需要一个脚本从第三行解析到CSV文件的末尾,忽略文件中level3
之前的值,然后传递这些值({{1 }和level3
)到level3
level4
我如何实现这一目标?请提出宝贵的建议。感谢您的帮助
答案 0 :(得分:4)
只要您确定数据中有从不任何逗号,您就可以使用split
。但即便如此,将分割限制为两个字段也是明智之举,这样你就可以获得第一个逗号及其后的所有内容
您的代码存在一些问题。首先,我希望您将use strict
和use warnings
放在所有Perl程序的顶部。这个简单的措施可以解决许多你可以忽略的微不足道的问题,所以在你寻求代码帮助之前这一点尤为重要
通常不知道,但在"\n"
字符串末尾添加换行符die
会阻止Perl在错误发生位置的输出中提供文件和行号详细信息。虽然这可能是你想要的,但给予额外信息通常会更有帮助
您的变量名称确实无用,并且按照惯例,Perl变量由小写字母数字和下划线组成。像@XYX
和$W
这样的名称根本无法帮助我理解您的代码!
而不是拆分为数组,看起来你最好将两个字段放入两个标量变量中以避免所有索引。我不确定你的意图@XYX = (["$data[1]","$data[1]"],)
。首先,你真的想要两次使用$data[1]
吗?其次,你应该从不将标量变量放在双引号中,因为它做了非常具体的事情,除非你知道那是什么,否则你应该避免它。最后,你是说每次围绕循环push
一个匿名数组到@XYX
吗?否则,每次从文件中读取一行时都会覆盖数组的内容,并且先前的数据将丢失
此程序使用正则表达式从第一个字段中提取$level_num
。它只是找到字符串中的第一个数字序列,然后可以将其与最小所需级别$min_level
进行比较,以确定日志中的一行是否相关
use strict;
use warnings;
my $file = 'xyz.csv';
my $min_level = 3;
my @list;
open my $fh, '<', $file or die "Could not open '$file' $!";
while (my $line = <$fh>) {
chomp $line;
my ($level, $error) = split ',', $line, 2;
my ($level_num) = $level =~ /(\d+)/;
next unless $level_num >= $min_level;
push @list, [ $level, $error ];
}
答案 1 :(得分:1)
为了决定要处理哪些记录,你可以沿着这些行使用“触发器”操作符(..
)。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my $level = shift || 'level1';
while (<DATA>) {
if (/^\Q$level,/ .. 0) {
print;
}
}
__DATA__
level1,er
level2,er2
level3,er3
level4,er4
触发器运算符返回false,直到其第一个操作数为真。此时它返回false,直到第二个操作数为真;此时它再次返回false。
我假设你的文件是订购的,所以一旦你开始处理它,你永远不想停止。这意味着触发器的第一个操作数可以是/^\Q$level,/
(匹配行开头的字符串$level
),第二个操作数可以只为零(因为我们从不希望它停止处理)。
我还强烈建议不使用split /,/
解析CSV记录。这可能适用于您当前的数据,但通常情况下,CSV文件中的字段允许包含嵌入式逗号,这将破坏此方法。相反,请查看Text::CSV或Text::ParseWords(包含在标准Perl发行版中)。
更新:我似乎对此有一些支持。如果人们花时间解释原因,那就太好了。
答案 2 :(得分:1)
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
my @XYZ;
my $file = 'xyz.csv';
open my $fh, '<', $file or die "$file: $!\n";
my $level = shift; # get level from commandline
my $getall = not defined $level; # true if level not given on commandline
my $parser = Text::CSV->new({ binary => 1 }); # object for parsing lines of CSV
while (my $row = $parser->getline($fh)) # $row is an array reference containing cells from a line of CSV
{
if ($getall # if level was not given on commandline, then put all rows into @XYZ
or # if level *was* given on commandline, then...
$row->[0] eq $level .. 0 # ...wait until the first cell in a row equals $level, then put that row and all subsequent rows into @XYZ
)
{
push @XYZ, $row;
}
}
close $fh;
答案 3 :(得分:0)
#!/usr/bin/perl
use strict;
use warnings;
open(my $data, '<', $file) or die "Could not open '$file' $!\n";
my $level = shift ||"level1";
while (my $line = <$data>) {
chomp $line;
my @fields = split "," , $line;
if($fields[0] eq $level .. 0){
print "\n$fields[0]\n";
print "$fields[1]\n";
}}
这很有效....感谢所有人的帮助......