Perl将File拆分为数组并从子例程读取

时间:2015-05-29 21:21:26

标签: arrays perl subroutine

我创建了一个子程序,用于在下面分隔的制表符中创建HoA。

header_map.txt:

def test_email(data)
  notif_type = data['notif_type']
  emails_list = ['132xxy@yahoo.com', '133xxy@yahoo.com']
  subject = case notif_type
  when 'test_case_1'
    "test1"
  when 'test_case_2'
    "test2"
  when 'test_case_3'
    "test3"
  mail(:to => emails_list, :subject => subject) do |format|
    format.html { render  :layout => 'layouts/newdesign' }
  end
end

sub然后将数组从给定键的值反弹(如下所示)。 其中值与数组匹配,索引为 返回匹配的数组元素。 我想要做的不是搜索预定义的常量数组, 我想搜索从文件中读取的数组,或者在本例中搜索数据。 下面是常量数组的工作代码。

account_number_header   account
account_number_header   Account #
account_number_header   Account No.
account_number_header   Account number
account_number_header   Account_Id
first_Name_header   name1
first_Name_header   first name
first_Name_header   account name1
first_Name_header   first_name
first_Name_header   f name
last_Name_header    name2
last_Name_header    last name
last_Name_header    account name2
last_Name_header    last_name
last_Name_header    l name
address_header  address1
address_header  address
address_header  addresses
address_header  place of residency
address_header  location

结果

my @fields = ('Account No.','name1','name2','location'); #array being searched
my $hm = "header_map.txt"; #declare variable to file
my $fh = (readfile($hm));  #declare variable to sub routine call

my $address_header = 'address_header'; #my given key
my $address = hashofarray($fh,$address_header); #looking for($fh,key) in sub
my $account_number_header = 'account_number_header'; #my given key
my $account_number = hashofarray($fh,$account_number_header); #looking for($fh,key) in sub
print $address,",",$account_number,"\n"; #prints desired array indexes of given keys

sub hashofarray {
    my $fh = shift;
    my $key = shift;
    my %hash;
    while (<$fh>) { # creating HoA
        chomp;
        my ( $key, $value  ) = split /\t/;
        push (@{ $header_map{$key} }, $value);
    }
    foreach my $key1 (@{$header_map{$key}}) {
        if (my @index = grep { $fields[$_] eq $key1 } 0..$#fields) {
            return $index[0];
        }
    }
}

sub readfile {
    my $file = shift;
    open my $f, '<', $file or die $!;
    return $f;
}

这很好,我想要的,但是我想从DATA文件中读取数组@fields。 这是我在阅读DATA时的尝试。

尝试失败

location,Account No.

我的结果

my $hm = "O:/josh/trade_data/mock_header_map.txt"; # declare variable to file
my $fh = (readfile($hm)); # declare variable to sub routine call

while (<DATA>) { # calling the subroutine after reading DATA
    my @fields = split /\t/;
    my $address_header = 'address_header'; # my given key
    my $address = hashofarray($fh, $address_header); # looking for($fh, key) in sub
    my $account_number_header = 'account_number_header'; # my given key
    # looking for($fh, key) in sub
    my $account_number = hashofarray($fh, $account_number_header);
    # prints desired array indexes of given keys
    print $address, ",", $account_number, "\n";
}

sub hashofarray {
    my $fh = shift;
    my $key = shift;
    my %hash;
    while (<$fh>) {  #creating HoA
        chomp;
        my ( $key, $value  ) = split /\t/;
        push (@{ $header_map{$key} }, $value);
    }
    foreach my $key1 (@{$header_map{$key}}) {
        if(my @index = grep { $fields[$_] eq $key1 } 0..$#fields) {
            return $index[0];
        } else {
            print "not found";
        }
    }
}

sub readfile {
    my $file = shift;
    open my $f, '<', $file or die $!;
    return $f;
}


__DATA__
Account No  name1   name2   location
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345

期望的结果

,
,
,
,
,

最后,我想打印所需的列,如果我可以将DATA读入数组,我将能够做到这一点,而不是因为sub不能识别@fields而得到空字符串。 我知道我需要对数组引用做一些事情,但我对这些有点偏僻......有什么建议吗?我希望这很清楚。

2 个答案:

答案 0 :(得分:1)

好的,好的。这里的核心问题是您的hashofarray函数尝试读取文件句柄。然后迭代到文件的末尾。然后......再次调用它,当没有更多文件可供阅读时。

但这不是唯一的问题 - 有几个问题。如果你从数组的散列中重写密钥......为什么不使用散列哈希呢? 你做

同样 - @fields不是全局范围的,因此当您尝试在hashofarray中重复使用时......它总是空的。

我可以建议退一步吗?用您的实际问题规范更新您的问题(或询问新问题)?包括输入数据和预期输出。

我认为您已经经历了几个修复此代码的周期,并且它变得混乱,所以我认为是时候退缩一点并重新开始。我想你会发现那里有更清洁,更优雅的解决方案。

那就是说 - 如果您只是想提取标题&#39;来自现有数据块的行:

my @fields = split /\t/,<DATA>; #read first line, split into array. 
while ( <DATA> ) { #etc.

您可以 - 例如 - 翻译您的数据&#39;像这样的数据结构:

use strict;
use warnings;
use Data::Dumper;
my @all_records;
my $header_line = <DATA>;
chomp($header_line);
my @headers = split /\t/, $header_line;
while (<DATA>) {
    chomp;
    my @columns = split /\t/;
    my %record;
    @record{@headers} = @columns;
    print Dumper \%record;
    push( @all_records, \%record );
}

print Dumper \@all_records;

foreach my $record ( @all_records ) { 
   print join ",", $record -> {'Account No'}, $record -> {'location'},"\n";
}

__DATA__
Account No  name1   name2   location
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345
1   josh    smith   411 s chirris ave. sometown st 12345

我建议 - 你可以使用&#39;帐号&#39;作为一个独特的键,可能所以你实际上并不需要使用数组。你在这个的情况下做了,所以我已经在我的代码中完成了这个。

这将打印:

1,411 s chirris ave. sometown st 12345,
1,411 s chirris ave. sometown st 12345,
1,411 s chirris ave. sometown st 12345,
1,411 s chirris ave. sometown st 12345,

答案 1 :(得分:0)

你在我的内部循环声明@fields

while (<DATA>) { # calling the subroutine after reading DATA
my @fields = split /\t/;

因此该变量的范围仅限于while循环。而不是这样做尝试在循环时声明数组@fields

另请将这些放在代码顶部。

use strict;
use warnings;

如果这些行位于顶部,您将发现此错误。

此外,您还需要改进阅读文件的方式。当您第一次阅读$fh时,搜索指针将最后到达,之后您的代码将永远不会从文件中读取任何内容。它将适用于第一次迭代中创建的哈希。因此,如果您只需一次阅读文件,请将该阅读部分从其他内容中取出,如果您想要一次又一次阅读,请关闭$fh并重新打开它。

if(my @index = grep { $fields[$_] eq $key1 } 0..$#fields) {不会提供来自@fields的实际字词,而是会提供来自@fields的匹配字词的索引,因此在打印时应该使用

print $fields[$address],",", $fields[$account_number], "\n";

我希望在完成这些更改之后,您将能够为您的问题撰写正确的解决方案。