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

Perl-通过哈希循环并更改内部迭代器计数器?,perl,hash,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>) {

我有一个杂烩:

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);
问题是,文本可能包含一个带有重复键的重复行,其中包含一个我不关心的重复信息


键为%myHash
内部迭代器。如果我找到了一个键,有没有办法修改内部迭代器,这样我在重置它之后就不会再对它进行迭代?

在我看来,你只是想在找到它后从%myHash中删除该键。

因为你不控制键的顺序,所以设置内部指针没有帮助。一旦你找到钥匙,你就可以简单地把它取下来。如果要保留已使用的哈希或将其移动到新的哈希,请先复制哈希,可能是
%used

更新 现在,您已经更好地解释了您需要什么,这段代码应该可以为您完成它。它保留一个哈希
%want
,其中包含要删除的列的名称 插入值及其对应的值

必须注意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 );

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

当您可以执行简单的
exists
lookup时,为什么还要迭代哈希?我可能错了,但听起来好像您试图将数据文件中的字段映射到数据库中的列名。你可以做到这一点,而不会弄乱散列的内部结构;请举例说明您的数据,我们可以帮助您提出更好的解决方案。(另请参见)我不确定
是否存在
是否会对我有所帮助。我想做的只是简化一些东西。我有一个输出,有很多行。我想把一行和正则表达式匹配起来。正则表达式是该行的一个子字符串。然后我想从行中删除正则表达式,这将为我提供所需的值。然后将该值上载到数据库。正则表达式是散列的
,子字符串在数据库中所处的列是散列的
。不,但我认为有一种更好的方法,为此我需要了解您正在尝试做什么。:-)看起来像是
%my_hash
应该是一个成对数组,而不是散列,因为您没有使用regex字符串访问hashKinda中的相应值,但实际上不是。我查看每个换行符的哈希,以便将该行与哈希的“键”匹配,哈希是用于匹配的正则表达式。我希望下一行读到的哈希完整无缺;每行中的每个键只查找一次;你想阻止查找什么?我在打电话,暂时没有文档链接。好的,成功了,我将删除放在第一个while循环中,并将原始哈希复制到第一个while循环之前的临时哈希中。这就解决了问题。@KingsInnerSoul:如果这是你唯一做的更改,而哈希的键实际上是正则表达式字符串,那么你的代码就不能像
索引那样工作,也不能搜索正则表达式模式。这就是我认为OP真正想做的。我会在表和列名中加上
quote\u identifier
,以防它们包含特殊字符,尽管这似乎不太可能。这不是我想要做的。散列的键只是我比较每行的正则表达式。找到该字符串的匹配正则表达式后,哈希值将用作数据库的列。我在每一列中输入的实际数据是字符串的其余部分——没有regex(has的键)@kingsynersoul:这应该成为你的问题。您成功地愚弄了至少两个一流的Perl程序员,认为您就是这样想的wanted@KingsInnerSoul:您是否意识到
索引
不会进行正则表达式匹配?它只是在另一个子字符串中查找一个子字符串。这就是您的示例代码具有误导性的原因之一。显示shell输出的示例也会有很大帮助command@Borodin你刚才叫我什么?!:D
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 );
my $lines = do {
    open my $cmd_fh, '-|', 'my shell command' or die "Can't exec: $!";
    local $/;
    <$fh>;
};

my @matching_keys = grep { index( $line, $_ ) >= 0 } keys %my_hash;
my @values        = @my_hash{@matching_keys};
my $columns       = join ', ', @matching_keys;
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 );