检查文件中是否有值:最佳和最快的做法?

时间:2014-02-13 14:58:11

标签: perl

我需要检查一个特定的值 - 一个没有空格的字符串 - 是否在一个文件中,在一个特定的位置。该文件包含各种数据行,每行包含由*和空格分隔的数据。我们寻找的值始终是每行的第六个值。防爆。 (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);

那么什么是最好和最快的练习(包括其他任何方式)?

3 个答案:

答案 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;