2016-09-25 32 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 
相關問題