2012-08-29 25 views
6

Tôi muốn tạo động một mã băm %detail mà không sử dụng câu lệnh eval. Mã này hoạt động tốt với tuyên bố eval, nhưng có cách nào tốt hơn để thực hiện việc này mà không sử dụng eval không?

my @input=('INFO: Vikram 32 2012','SAL: 12000$','ADDRESS: 54, junk, JUNK'); 

my %matching_hash= (
        qr/^INFO:\s*(\S+)\s+(\S+)\s+(\S+)/ =>['name','age','joining'], 
        qr/^SAL:\s*(\S+)/ => ['salary'], 
        qr/ADDRESS:\s*(.*)/ =>['address'] 
        ); 
my %detail; 
while(my ($regex, $array) = each(%matching_hash)) { 
    foreach (@input){ 
     if(/$regex/) { 
      for(my $i=0;$i<=$#$array; $i++) { 
       $j=$i+1; 
       eval '$detail{$array->[$i]} = $$j'; 
      } 
     } 
    } 
} 
use Data::Dumper; 

print Dumper(\%detail); 
++++++++++++++ 

$VAR1 = { 
      'name' => 'Vikram', 
      'address' => '54, junk, JUNK', 
      'age' => '32', 
      'joining' => '2012', 
      'salary' => '12000$' 
     }; 
+0

Tôi không nghĩ câu lệnh eval của bạn sẽ hoạt động nếu bạn 'sử dụng nghiêm ngặt' (tôi phải xóa nó khỏi thử nghiệm của mình để có được kết quả mong muốn). –

Trả lời

5

Thay đổi vòng lặp for:

for(my $i=0;$i<=$#$array; $i++) { 
    $j=$i+1; 
    eval '$detail{$array->[$i]} = $$j'; 
} 

bởi:

@detail{@{$array}} = ($_ =~ $regex); 
1

Bạn có thể sử dụng hai mảng @LAST_MATCH_START@LAST_MATCH_END (xem perldoc perlvar) cùng với substr thay vì $1, $2.... Một cái gì đó tương tự như

$detail{ $array->[$i] } = substr $_, $LAST_MATCH_START[$j], $LAST_MATCH_END[$j] - $LAST_MATCH_START[$j]; 
+0

Đồng ý, ngoại trừ 'English'. – hobbs

14

phần liên quan:

if(my @m = /$regex/) { 
    for(my $i=0;$i<=$#$array; $i++) { 
     $detail{$array->[$i]} = $m[$i];    
    } 
} 
2

Nếu bạn có thể sử dụng phiên bản mới nhất của Perl, xem ký hiệu này (?<name>...) trong regexp perlre docs Rõ ràng hơn sau đó sử dụng $ 1, $ 2, $ 3, vv

SCRIPT

use v5.14; 
use Data::Dumper; 

my @inputs = ('INFO: Vikram 32 2012', 'SAL: 12000$','ADDRESS: 54, junk, JUNK'); 

my %matching_hash= (
    qr/^INFO:\s*(?<name>\S+)\s+(?<age>\S+)\s+(?<joining>\S+)/ => [ 'name', 'age', 'joining' ], 
    qr/^SAL:\s*(?<salary>\S+)/        => [ 'salary' ], 
    qr/ADDRESS:\s*(?<address>.*)/        => [ 'address' ], 
); 

my %detail; 
while (my ($regex, $array) = each %matching_hash) { 

    INPUT: 
    foreach my $input (@inputs) { 

     next INPUT if not $input =~ m{$regex}; 

     for my $name (@$array) { 
      $detail{$name} = $+{$name}; 
     } 
    } 
} 

say Dumper(\%detail); 

OUTPUT

$VAR1 = { 
      'name' => 'Vikram', 
      'address' => '54, junk, JUNK', 
      'age'  => '32', 
      'joining' => '2012', 
      'salary' => '12000$' 
     }; 
+2

Anh ta không cần các mảng được ánh xạ nếu anh ta sẽ sử dụng các kết quả được đặt tên chỉ ''detail {keys% +} = values% + nếu $ input = ~ m {$ regex};' hoặc thậm chí '% detail =% + if $ input = ~ m {$ regex}; '. Sau đó, bạn có thể đặt các regex vào một cấu trúc phù hợp hơn cho việc lặp lại, một danh sách/mảng. 1 cho những gì tôi đã đề nghị. – Axeman

+0

'% detail =% + nếu $ input = ~ m {$ regex};' sẽ không hoạt động, nó sẽ ném đi những gì đã có trong '% detail'. –

1

Sử dụng named capture groups, bạn có thể loại bỏ nhu cầu %matching_hash là một băm. Trong khi đồng thời loại bỏ sự cần thiết phải sử dụng các biến số, hoặc chỉ định kết quả của trận đấu trong một mảng. Điều này là do nó sẽ lưu trữ thông tin liên quan vào %+.

use 5.10.1; 

my @match = (
    qr'^INFO:\s*(?<name>\S+)\s+(?<age>\S+)\s+(?<joining>\S+)', 
    qr'^SAL:\s*(?<salary>\S+)', 
    qr'ADDRESS:\s*(?<address>.*)', 
); 

sub get_details{ 
    my %detail; 

    for my $input (@_) { 
    for my $match (@match){ 
     next unless $input =~ $match; 
     @detail{keys %+} = values %+; 
     last; 
    } 
    } 

    return \%detail; 
} 

use Data::Dumper; 
my @inputs = ('INFO: Vikram 32 2012', 'SAL: 12000$','ADDRESS: 54, junk, JUNK'); 
say Dumper get_details @inputs 

Có thể đơn giản hơn nếu bạn kết hợp số qr thành một.

use 5.10.1; 

my $match= qr" 
    ^INFO: \s* (?<name>\S+) \s+ (?<age>\S+) \s+ (?<joining>\S+) 
    | ^SAL: \s* (?<salary>\S+) 
    | ADDRESS: \s* (?<address>.*) 
"x; 

sub get_details{ 
    my %detail; 

    for my $input (@_) { 
    $input =~ $match; 
    @detail{keys %+} = values %+; 
    } 

    return \%detail; 
} 

use Data::Dumper; 
my @inputs = ('INFO: Vikram 32 2012', 'SAL: 12000$','ADDRESS: 54, junk, JUNK'); 
say Dumper get_details @inputs 
Các vấn đề liên quan