6

我对 Perl 很陌生,需要你的帮助

我有一个xyz.csv包含内容的 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,并将这些值 ( level2to level4) 传递给@XYX = (["$data[1]","$data[1]"],);}

level2,er2
level3,er3
level4,er4

我输入level3,所以我需要一个脚本来从第三行解析到 CSV 文件的末尾,忽略文件中之前的值level3,并将这些值(level3level4)传递给@XYX = (["$data[0]","$data[1]"],);}

level3,er3
level4,er4

我该如何做到这一点?请务必提出您宝贵的建议。我感谢您的帮助

4

4 回答 4

4

只要您确定数据中没有任何逗号,您就可以使用split. 但即便如此,将拆分限制为两个字段是明智的,这样你就可以得到第一个逗号和它之后的所有内容

您的代码存在一些问题。首先,我希望您将use strictanduse 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 ];
}
于 2012-08-31T12:57:09.593 回答
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,直到它的第二个操作数为 true;此时它再次返回 false。

我假设您的文件是有序的,因此一旦您开始处理它,您就永远不想停止。这意味着触发器的第一个操作数可以是/^\Q$level,/(匹配行首的字符串$level),第二个操作数可以是零(因为我们不希望它停止处理)。

我还强烈建议不要使用split /,/. 这可能适用于您当前的数据,但一般来说,CSV 文件中的字段允许包含嵌入的逗号,这会破坏这种方法。相反,请查看Text::CSVText::ParseWords(包含在标准 Perl 发行版中)。

更新:我似乎对此有一些反对意见。如果人们愿意花时间解释原因,那就太好了。

于 2012-09-01T12:30:05.043 回答
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;
于 2012-09-02T13:38:23.093 回答
1
#!/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";
}}

这有效....感谢大家的帮助...

于 2012-09-03T09:03:58.510 回答