【问题标题】:Directly substitute or match and substitute in perlperl中直接替换或匹配替换
【发布时间】:2013-07-02 04:15:11
【问题描述】:

有一个包含 milions++ 行的文件。有些行的形式是

123456_654321_some-random-text ( e.g. /\d{6}_\d{6}_(.*)/ )

别人只是

some-random-text

和其他人又不同了……

从我的第一个示例中删除前 14 个字符的最快方法是什么?

while(<>) {
    chomp;
    s/^\d{6}_\d{6}_//;  # so simple trying to substitute from every line
                        # and substitute will fail anyway when doesn't match
}

或

while(<>) {
    chomp;
    s/^.{14}// if m/^\d{6}_\d{6}_/;  # with condition...
}

就速度(和正确性)而言,这并不重要...

【问题讨论】:

  • 查看Benchmark 模块并亲自查看。
  • @mob 也许其他人会有同样的问题 - 但好吧 - 这也是一个答案......
  • 我希望第一种形式(省略 if 子句)运行得更快——但是,当然,没有基准测试就无法确定。
  • 您为什么关心速度?你将不得不一遍又一遍地运行这个程序吗?我怀疑字符串操作方法的任何差异都会被读取数百万行文本的磁盘 I/O 相形见绌,所以你使用哪种技术并不重要。
  • @AndyLester,处理数百万行很糟糕。他希望它少吸一点。他不能通过减少数百万行来减少它的吸引力。渴望对常数因素进行“微观”优化的非常直接的理由——这些是他唯一可以优化的因素。是的,他会不止一次地运行它:这就是为什么他在这里,询问,而不是已经解决了其他问题。你只是在告诉他离开你的草坪。

标签: perl


【解决方案1】:

这与您使用的内容几乎无关。您可以运行此基准测试:

$ perl <<'END'
use strict;
use warnings;
use Benchmark qw ( :all );

my @str = ('123456_654321_some-random-text' x 100, 'some text' x 50);

cmpthese( 3_000_000, {
     'regex'  => sub { map s/^\d{6}_\d{6}_//,                 @str; },
     'regex1' => sub { map /^\d{6}_\d{6}_/ && s/^.{14}//,     @str; },
     'split'  => sub { map /^\d{6}_\d{6}_/ && (split /_/)[2], @str; },
     'substr' => sub { map /^\d{6}_\d{6}_/ && substr($_, 14), @str; },
});
END

对我来说,对于如此少量的迭代,这会产生不确定的结果。结果还取决于月相和匹配线与不匹配线的比率(此处为:2:1,但也可以是1:3)。

一般来说,我更喜欢s/^\d{6}_\d{6}_//,因为这样可以减少重复工作,而且阅读起来最清晰。

关于运行更长的基准测试

my @str = ('123456_654321_some-random-text' x 100, 'some text' x 50)x100;

我得到了以下结果:

          Rate  split regex1 substr  regex
split  39139/s     --   -12%   -14%   -18%
regex1 44603/s    14%     --    -2%    -7%
substr 45338/s    16%     2%     --    -5%
regex  47740/s    22%     7%     5%     --

它更喜欢这种简单的替换。但substr 也不甘落后。然而,这些基准是相当人为的:只有一个匹配和一个不匹配的字符串,它们出现在 50-100 个字符串的连续序列中。这不会对实际数据进行建模,实际数据要随机得多。

【讨论】:

  • 非常感谢。这真的很有帮助。
【解决方案2】:

您要删除前 14 个字符吗?

我打赌substr 会比正则表达式匹配更快。

作为 Perl 程序员,我们非常喜欢正则表达式,我们有时会忘记非正则表达式的处理方式,而这些方式通常更快。

使用

while( my $line = <> ) {
    chomp $line;
    $line = substr($line, 14);
}

使用Benchmark 模块看看。

【讨论】:

  • 他只想删除第一个示例中的前 14 个字符,而不是第二个。这里将需要正则表达式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-06
  • 2011-02-15
相关资源
最近更新 更多