我需要检查一个特定的值 - 一个没有空格的字符串 - 是否在一个文件中,在一个特定的位置。该文件包含各种数据行,每行包含由*和空格分隔的数据。我们寻找的值始终是每行的第六个值。防爆。 (otherval1 * otherval2 * otherval3 * otherval4 * otherval5 * value-to-get *等)但是可以在一行中的另一个位置找到相同的值。但我们不想获得这个价值。在此检查期间,其他用户可以打开该文件,因此需要进行群集。什么是最好和最快的方法。我可以想到两种方式:
my $value = "qt7nxve";
my $completed = 0; #if the value is found in the file at the sixth position of a line, $completed will take the value of 1.
第一种方式:在数组中收集数据
open(INFO, "$outfile1") or die ("Couldn't open datafile");
flock(INFO, 2);
my @datadone = <INFO>;
close(INFO);
foreach my $line (@datadone) {
my @liner = split(/\* /, $line);
if ($liner[5] eq $value) { $completed = 1;}
}
第二种方式:使用while和数组
open(INFO, "$outfile1") or &dienice("Couldn't open datafile");
flock(INFO, 2);
while (<INFO>) {
my @datadone = <INFO>;
foreach my $line (@datadone) {
my @liner = split(/\* /, $line);
if ($liner[5] eq $value) { $completed = 1; }
}
}
close(INFO);
以下代码显示得更快,但无法使用,因为它可以在一行中找到除第六个位置之外的其他位置的值,$ completed将错误地取值为1。
open(INFO, "$outfile1") or die ("Couldn't open datafile");
flock(INFO, 2);
while (<INFO>) {
if ( $_ =~ m/$value/) {
$completed = 1;
}
}
close(INFO);
那么什么是最好和最快的练习(包括其他任何方式)?
答案 0 :(得分:4)
一旦找到匹配项,请考虑使用last
保留您正在使用的任何循环结构:
my $completed = 0;
while (<INFO>) {
my @data = split /\* /, $_;
if ($data[5] eq $value) {
$completed = 1;
last;
}
}
答案 1 :(得分:2)
我能想到的最快的是让正则表达式为你做列计数:
qr/ (?: # open non-capturing group
.*? # anything up until...
\* [ ] # a star and a space
){5} # five of these groups
value-to-get # the literal value you are looking for
\* [ ] # closed by a star and a space
/x; # <- allows eXpanded notation
因为您指定'* '
作为列分隔符,所以该列必须停在'* '
之前进行谨慎匹配(.*?
),这意味着它匹配除分隔符之外的所有内容。因此,您希望找到其中的5个分组,然后找到您要查找的值,然后是'* '
。
如果这匹配,我会把这样的行放在:
last if $completed = m/(?:.*?\*[ ]){5}value-to-get\*[ ]/;
这种方法假设没有一些精心设计的转义或引用协议允许列中的文字'* '
。
答案 2 :(得分:1)
你问过最好最快的方法,但你没有说明“最好”的意思;也没有任何理由相信你没有尝试过早优化。记住这些要点,这是 解决方案。
在处理分隔数据时,我喜欢使用Text::CSV。您可以使用任何单字节字符作为分隔符。如果您还安装了Text::CSV_XS,您将获得性能提升。如果在文件中的任何位置的第六列中找到指定的值,则以下将打印found
。一旦找到匹配,解析就会停止。
请注意,如果您的任何字段可以包含*
个字符,则此操作无效(除非CSV规范中存在某种引用机制)。
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Text::CSV;
my $csv = Text::CSV->new({
sep_char => '*',
allow_whitespace => 1,
binary => 1,
auto_diag => 1
}) or die "Cannot use CSV: " . Text::CSV->error_diag();
open my $fh, '<', 'infile' or die $!;
my $found;
my $value = 'qt7nxve';
while (my $row = $csv->getline($fh)) {
if ($row->[5] eq $value) {
$found = 1;
last;
}
}
close $fh;
say 'found' if $found;