【问题标题】:Sorting perl arrays to fixed order将 perl 数组排序为固定顺序
【发布时间】:2017-08-08 22:10:37
【问题描述】:

您好,我有一个包含以下键和值的数组:

 atest, 2
 ctest, 3
 btest, 8
 ftest, 1
 gtest, 6

然后我将它们从一个文件解析成一个数组。现在我想每次都按该顺序返回它们,就像 CSV 一样。 但是我无法让它工作。

来源:

 #!/usr/bin/env perl
 use warnings;
 use strict;


 my @data;
 my %tags;
 my $cur_tag;
 my ($tag,$line);
 open (FILE, '<', $ARGV[0]) or die "Could not open file: $!";
 while (<FILE>) {
chomp;
if (/^(MyValStart)/)
    { push @data, {} }
elsif (  ($tag,$line) = (/^\s*(atest)\s+(.+)$/)) {
    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif (  ($tag,$line) = (/^\s*(ctest)\S\s+(.+)$/)) {

    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    #print ($line,"\n");
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif (  ($tag,$line) = (/^\s*(itest)\S\s+(.+)$/)) {

    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif (  ($tag,$line) = (/^\s*(btest)\S\s+(.+)$/)) {

    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif (  ($tag,$line) = (/^\s*(ytest)\S\s+(.+)$/)) {

    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif (  ($tag,$line) = (/^\s*(ftest)\S\s+(.+)$/)) {

    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif (  ($tag,$line) = (/^\s*(gtest)\S\s+(.+)$/)) {

    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif (  ($tag,$line) = (/^\s*(utest)\S\s+(.+)$/)) {

    $data[-1]{$tag} .= " NEWLINE " if exists $data[-1]{$tag};
    $data[-1]{$tag} .= $line;
    $tags{$tag}++;
    $cur_tag = $tag;
}
elsif ($cur_tag) {
    $data[-1]{$cur_tag} .= " NEWLINE ".$_;
}
 }

 use Text::CSV;
 my $csv = Text::CSV->new({binary=>1,auto_diag=>2,eol=>"\n",
sep_char=>";",always_quote=>1,blank_is_undef=>1});
%tags=qw/atest ctest btest ftest gtest/;

$csv->print(select, [%tags]);
for my $row (@data) {
my @vals = map { $row->{$_} } %tags;
$csv->print(select, \@vals);
 }

从源代码可见,还有一些我解析到数组中的东西后来不用于打印输出。 这两个问题我都解决不了。

我想要的输出只针对 atest、ctest、btest、ftest 和 gtest 的值,如

"2"; "3"; "8"; "1"; "6"
"1"; "5"; "2"; "0"; "5"

返回的数字也可以是多行的单词或句子,但这已经奏效了。

输入文件是这样的:

 MyValStart
 ---------------

     atest:    2
     ctest:    3
     itest:    3
     btest:    8
     ytest:    3
     ftest:    1
     gtest:    6
     utest:    348385fhjdhgofdgkdfjgd



 MyValStart
 ---------------

     atest:    1
     ctest:    5
     itest:    3
     btest:    2
     ytest:    jfdgdf ifdgijfdjgoksfk iosjfdjdisfpgj
     ftest:    0
     gtest:    5
     utest:    jfsdhgjfd fighfidhg ifhdghfid ifdhjgifdh

关于如何解决此问题以使其正常工作的任何想法?

提前致谢。

【问题讨论】:

  • 您能否为所提供的输入示例提供相应的输出示例,因为不清楚您期望的输出是什么?
  • Re "我有一个包含以下键和值的数组:",这没有意义。数组键是数字。

标签: arrays perl sorting hash


【解决方案1】:

如果我正确地阅读了您的代码,那么您这样做是非常困难的。相反,我建议您应该做的是将您的输入读取并解析为合理的数据结构,然后以所需的格式输出。

由于您拥有带有键值对的“数据”块,并且您需要提取命名值 - 哈希数组将成为这项工作的工具。将每个“块”读入哈希,然后将其插入数组。

然后获取该哈希数组,并使用hash slices 提取您想要的值 - 按键排序。

类似这样的:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;

#read input data:
my @rows; 

#set record separator to 3 line feeds.     
local $/ = "\n\n\n";
while ( <> ) {
   next unless m/test/;
   #map key-values out of this 'chunk'. 
   my %row = m/(\w+):\s*(\S.*)/g; 
   push @rows, \%row; 
}

#print whole data structure for debugging:
print Dumper \@rows;

#define columns and ordering for output:
my @output_cols = qw ( atest ctest btest ftest gtest );

#iterate rows
foreach my $row ( @rows ) {
    #print fields selected from output_cols. 
   #use a 'hash slice' - look it up in perl docs. 
   print join ";", @{$row}{@output_cols},"\n"
}

这给出了

的输出
2;3;8;1;6;
1;5;2;0;5;

我们使用记录分隔符$/ 将我们的输入分成不是“默认”换行符的块。

这和你问的不太一样,因为没有引号。如果你想要,你可以map:

print join ";", (map { '"'.$_.'"' } @{$row}{@output_cols}),"\n"

但我不确定大多数csv 消费者是否有必要这样做。

【讨论】:

  • 如果这个词不是 atest btest 等,而是说风险、测试、总计等...我要如何更改 m/test/ 行才能正常工作?跨度>
  • m/test 行只是为了捕捉空的“块”,所以任何关键字。将其注释掉应该 有效,但如果您的输入文件中有其他内容,您可能会得到一些“空”行。否则m/MyValStart/ 应该可以解决问题
  • 谢谢,但我在scanner4.pl第28行,块6的连接或字符串中使用未初始化的值。不知道为什么
  • 可能意味着没有所有值的行,这将给出该错误。检查Dumper 输出(或打印输出),看看是否符合您的预期。
  • 有些东西在垃圾箱中没有被读取
猜你喜欢
  • 1970-01-01
  • 2016-05-24
  • 2015-01-17
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多