我遇到了一个子程序的问题,该子程序找到某些文件并从中提取一些数据。
在foreach循环中调用此子例程,但无论何时调用,循环都会跳到下一次迭代。所以我想知道下一个是否会以某种方式从子例程转移到foreach循环中调用它?
据我所知,该子看起来很稳固所以我希望有人能看到我失踪的东西吗?
sub FindKit{
opendir(DH, "$FindBin::Bin\\data");
my @kitfiles = readdir(DH);
closedir(DH);
my $nametosearch = $_[0];
my $numr = 1;
foreach my $kitfile (@kitfiles)
{
# skip . and .. and Thumbs.db and non-K-files
if($kitfile =~ /^\.$/) {shift @kitfiles; next;}
if($kitfile =~ /^\.\.$/) {shift @kitfiles; next;}
if($kitfile =~ /Thumbs\.db/) {shift @kitfiles; next;}
if($kitfile =~ /^[^K]/) {shift @kitfiles; next;}
# $kitfile is the file used on this iteration of the loop
open (my $fhkits,"<","data\\$kitfile") or die "$!";
while (<$fhkits>) {}
if ($. <= 1) {
print " Empty File!";
next;
}
seek($fhkits,0,0);
while (my $kitrow = <$fhkits>) {
if ($. == 0 && $kitrow =~ /Maakartikel :\s*(\S+)\s+Montagekit.*?($nametosearch)\s{3,}/g) {
close $fhkits;
return $1;
}
}
$numr++;
close $fhkits;
}
return 0;
}
答案 0 :(得分:1)
总结评论,重构代码:
use File::Glob ':bsd_glob';
sub FindKit {
my $nametosearch = $_[0];
my @kitfiles = glob "$FindBin::Bin/data/K*"; # files that start with K
foreach my $kitfile (@kitfiles)
{
open my $fhkits, '<', $kitfile or die "$!";
my $kitrow_first_line = <$fhkits>;
1 while <$fhkits>; # check number of lines ...
return if $. == 1; # there was only one line, the header
my ($result) = $kitrow_first_line =~
/Maakartikel :\s*(\S+)\s+Montagekit.*?($nametosearch)\s{3,}/;
return $result if $result;
}
return 0;
}
我使用核心File::Glob并启用:bsd_glob
选项,它可以处理文件名中的空格。我按照文档说明在Win32系统上使用“ real slash ”。
除了返回值之外,我没有看到它如何影响调用代码。此外,我也看不到发布的代码如何使调用者跳过节拍。这个问题不太可能出现在这个问题上。
如果我错过了上述重写的一些内容,请告诉我。
答案 1 :(得分:1)
这几乎肯定会让你感到困惑的是,你正在shift
你正在迭代的列表。
这是个坏消息,因为你正在删除元素......但是在某些地方你并不一定在思考。
例如:
#!/usr/bin/env perl
use strict;
use warnings;
my @list = qw ( one two three );
my $count;
foreach my $value ( @list ) {
print "Iteration ", ++$count," value is $value\n";
if ( $value eq 'two' ) { shift @list; next };
}
print "@list";
您认为应该迭代多少次,哪些值最终应该在数组中?
因为你shift
你永远不会处理元素&#39;三&#39;并删除元素&#39; one&#39;。这几乎可以肯定是什么导致了你的问题。
您还:
open
使用相对路径,当opendir
使用绝对路径时。 K
开头的内容。为什么不只搜索做以K
开头的内容? -z
会做得很好。$kitrow
,但并不是真的将它用于模式匹配以外的任何内容。它可能使用隐式变量更好地工作。 $numr
似乎被丢弃了)。 g
标志似乎多余。 我建议进行重大改写,并执行以下操作:
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
sub FindKit{
my ($nametosearch) = @_;
my $numr = 1;
foreach my $kitfile (glob "$FindBin::Bin\\data\\K*" )
{
if ( -z $kitfile ) {
print "$kitfile is empty\n";
next;
}
# $kitfile is the file used on this iteration of the loop
open (my $fhkits,"<", $kitfile) or die "$!";
<$kitfile> =~ m/Maakartikel :\s*(\S+)\s+Montagekit.*?($nametosearch)\s{3,}/
and return $1;
return 0;
}
}
答案 2 :(得分:1)
作为Path::Tiny模块的忠实粉丝(我总是在每个项目中安装并使用它),我的解决方案是:
groups = [[],['A','B']]
一些评论仍未解决问题:
>>> {k:head for head, *tail in grps for k in tail}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <dictcomp>
ValueError: not enough values to unpack (expected at least 1, got 0)
也适用于Windows。use strict;
use warnings;
use Path::Tiny;
my $found = FindKit('mykit');
print "$found\n";
sub FindKit {
my($nametosearch) = @_;
my $datadir = path($0)->realpath->parent->child('data');
die "$datadir doesn't exists" unless -d $datadir;
for my $file ($datadir->children( qr /^K/ )) {
next if -z $file; #skip empty
my @lines = $file->lines;
return $1 if $lines[0] =~ /Maakartikel :\s*(\S+)\s+Montagekit.*?($nametosearch)\s{3,}/;
}
return;
}
和data/file
... $0
读取所有行 - 不必要 - 但是对于小文件并不重要。realpath
的arg,所以可能更好的名称是my @lines = $file->lines;
或Maakartikel
:)find_articel_by_kit
- 只需将find_articel
更改为utf8