Perl - 循环哈希并更改内部迭代器计数器?

时间:2015-08-11 15:42:28

标签: perl hash

我有一个哈希:

my %myHash= (
    "Key1", "val1",
    "Key2", "val2",
    "Key3", "val3",
    "Key4", "val4"
);

我循环了

open(EXEC, '-|', "my Shell Command") or die "Can't exec: $!\n";

# Now read the output just like a file
while(my $line = <EXEC>) {
    chomp $line;             # remove the newline from the read line
    $line =~ s/^\s+|\s+$//g; # remove leading or trailing whitespaces
    # reset the internal iterator, and loop through the hash
    keys %myHash;
    while(my($key, $val) = each %myHash) {
        # find if it matches anything - and store it
        my $keyWordIndex = index($line, $key);
        if ($keyWordIndex != -1) {
            # if the cols/vals query isnt empty, add comma to the end
            if (length($queryCols) > 1) { $queryCols .= ", "; }
            if (length($queryVals) > 1) { $queryVals .= ", "; }

            # do some more stuff here
            my $subLine  = substr($line, $someStart, $someLength);
            # now build the columns and values to write out to the DB
            $queryCols .= $val;
            $queryVals .= "'$subLine'";
        }
    }
}
# prepare the DB query
$command = $dbConnection->prepare("INSERT INTO $table($queryCols) VALUES ($queryVals)")
or die "Could not prepare the query - $DBI::errstr\n";

# execute the database update
eval { 
    my $db_results = $command->execute();
};

close(EXEC);

我在while循环中执行的操作是逐行查看文本,并寻找与keys之一匹配的内容。上面的while循环嵌套在另一个while循环内,该循环逐行读取文本。如果有匹配,我会收到一个字符串,然后我用它来更新我的数据库。字符串I concatinate是散列中匹配键的值。

所以我的SQL查询看起来像这样:

INSERT INTO myTable(header1, header3, header2, header4)
VALUES ('substr1','substr3','substr2','substr4');

问题是,文本可能包含带有重复键的重复行,该重复键具有我不关心的重复信息。

keys %myHash resets内部迭代器。如果我找到了一个键,有没有办法修改内部迭代器,所以在重置之后我不会再次迭代它?

3 个答案:

答案 0 :(得分:4)

更新

现在你已经解释了你需要的更好一点,这段代码应该为你做。它保留一个哈希%wanted,其中包含要列的名称 插入及其对应的值

您必须注意列命名和数据值之间的shell命令输出中出现的任何空格:散列中的正则表达式必须允许它,或者您必须在模式中包含\s*应用

my $table;

open my $cmd_fh, '-|', 'my shell command' or die "Can't exec: $!";

my %wanted;

while ( <$cmd_fh> ) {
    s/\s+\z//;
    while ( my ($re, $column) = each %my_hash ) {
        if ( / $re (.*) /x ) {
            %wanted{$column} //= $1;
        }
    }
}

my @values        = values %wanted;
my $columns       = join ', ', keys %wanted;
my $placeholders  = join ', ', ( '?' ) x @values;

my $sql = sprintf 'INSERT INTO %s (%s) VALUES (%s)', $table, $columns, $placeholders;
my $command = $dbh->prepare( $sql );
$command->execute( @values );


如果我理解正确,您希望从您的哈希中选择那些出现在shell命令输出中的密钥。然后,您希望使用这些键作为列名执行SQL INSERT语句,并将相应的哈希值作为要插入的数据

你做的事情比必要的要复杂得多。此代码将整个文件读入变量$lines,然后调用grep来挑选出现在$lines

中任意位置的哈希键

从那里可以很容易地生成以逗号分隔的列名列表和相应的占位符问号列表,这些问号可用于创建传递给INSERT的{​​{1}}语句。哈希值列表传递给prepare,它将根据数据类型

正确引用它们
execute

你显然习惯用不同的语言写作。你应该坚持使用小写字母作为词汇标识符。 Perl为全局标识符保留大写字母,例如包名称

答案 1 :(得分:2)

由于您不控制键的顺序,因此设置内部指针无济于事。一旦找到密钥,您只需delete密钥即可。如果要挂起使用过的或者将它们移动到新的哈希值,可以先复制哈希值,也许%used

答案 2 :(得分:1)

听起来像你只想在找到它后从%myHash中删除密钥。