2016-09-25 119 views
0

我有3个分隔符(:,和;)的数据并且在数据中:和;通过使用3个分隔符分割数据,并将其一次存储在2个独立数组中

分割::只出现一次

__DATA__ 

1:X,Y,X,A,B;C,D,E,F 
2:A,C,B,D 
3:W,R,T,E;E 

步骤1,并建立一个散列

步骤2:通过

分割,并存储每一个逗号分隔值直到找到为止;

步骤3:遵循

一切;将在另一个阵列

从上面的数据,我试图存储所有的值;在数组B中

Output 
A = [X,Y,X,B,A,B,C,D,W,R,T,E] B=[C,D,E,F,E] 

下面阵列A和一切右边是我试图

my (@A,@B); 
sub Compare_results 
{ 
    my %result_hash = map { chomp; split ':', $_ } <DATA> ; #split by colon and futher split by , and ; if any (doing it in insert_array) 
foreach my $key (sort { $a <=> $b } (keys %result_hash)) 
{ 

    @A = split ",", (/([^;]+)/)[0], $result_hash{$key}; 
    @B = split ",", (/;([^;]+)/)[0], $result_hash{$key}; 
    print Dumper \@A,\@B; 
}  

} 

代码但这不是产生任何结果,输出阵列是空 请告诉我的正确的方法按数据分割数据,在单独的数组 时间存储器有也是一个办法由三个分隔符拆分数据(一个分裂为建立一个哈希)在一个拍摄

感谢

+0

代码如何失败?它在生产什么? – choroba

+0

@choroba它没有打印任何内容,如果你不理解,试图理解 – LearningCpp

+0

,你试图用'map'过于聪明。 – Sobrique

回答

2

许多问题:open需要一个文件名,而不是文件句柄内容(除非DATA包含文件名,否则不包含)。要保留数组中的值,请使用push,而不是赋值 - 无论如何,无论如何,您无法将其分配给两个数组,因为第一个数组可以吃掉所有数据。而且,在一个命令中做所有事情都是可能的,但绝对不可读和可维护。

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

my $fh = *DATA{IO}; 
my (@A, @B);           # The comments just fix 
                 # the stupid SO syntax highlighter. 
my %result_hash = map { chomp; split /:/ } <$fh>;  #/ 
for my $key (sort { $a <=> $b } keys %result_hash) { 
    my ($left, $right) = split /;/, $result_hash{$key}; #/ 
    push @A, split /,/, $left;       #/ 
    push @B, split /,/, $right // q(); 
} 

use Data::Dumper; print Dumper(\@A, \@B, \%result_hash); 

__DATA__ 
1:X,Y,X,A,B;C,D,E,F 
2:A,C,B,D 
3:W,R,T,E;E 
0

诀窍是每个步骤分开,并以不同的顺序。订单是tokenize,然后解析。基本上,把它分解成碎片,然后用这些碎片做一些事情。

下一个技巧是递归地标记。这不是试图一次性标记所有东西,而是将大的令牌分成小的令牌,然后把小的令牌分成更小的令牌,等等直到你触底为止。首先是行,然后是CSV。

这样看,语法的第一层看起来像这样(空白被忽略)。

LINE = LINENUM : CSV ; CSV 

请注意,在这一点上我们不关心CSV中的内容。我们假设我们不必处理引用和转义,否则事情变得复杂。

有几种方法可以解决这个问题。一种是使用正则表达式一次性标记整个事物。

my($linenum, @csvs) = $line =~ /^(.*?) : ([^;]*) ; (.*)$/x; 

现在,你有@csvs从一切他们需要被标记化分离。你可以通过分割逗号将它们变成更多的标记。

push @$a, split /,/, $csvs[0]; 
push @$b, split /,/, $csvs[1]; 

然后你去了。通过对每一层进行标记,您可以避免尝试一次解析所有内容的复杂性。


至于你的功能,有很多事情可以做,以改善它。主要有一件事,解析文件。别的东西打开文件。

它所需要的一切都应该传入并返回,不使用全局变量(是的,函数外部的my算作全局变量)。

use strict; 
use warnings; 
use v5.10; # for say() 

my($left, $right) = parse_whatever_this_format_is_called(*DATA); 

say "Left: ". join ", ", @$left; 
say "Right: ". join ", ", @$right; 

sub parse_whatever_this_format_is_called { 
    # Take the filehandle to read as input 
    my $fh = shift; 

    # Declare our outputs 
    my(@left, @right); 

    # Parse each line 
    while(my $line = <$fh>) { 
     # Tokenize LINE = LINENUM : CSV ; CSV 
     my($linenum, @csvs) = $line =~ /^(.*?) : ([^;]*) ; (.*)$/x; 

     # Skip lines that didn't match 
     next if !$linenum; 

     # Split the CSVs 
     push @left, split /,/, $csvs[0]; 
     push @right, split /,/, $csvs[1]; 
    } 

    # Return our outputs as references. 
    # It's the only way to return multiple lists. 
    # Also it avoids the expense of a copy. 
    return(\@left, \@right); 
} 

__DATA__ 
1:X,Y,X,A,B;C,D,E,F 
2:A,C,B,D 
3:W,R,T,E;E 
相关问题