在Perl中,如何加速正则表达式修改一个非常大的字符串?

时间:2012-12-11 17:03:33

标签: regex string perl

我有一个由3亿个碱基组成的字符串;

$str = "ATCGTAGCTAGXCTAGCTAGCTGATXXXXATCGTAGCTAGCTGXTGCTAGCXXXXA...A";

我想将字符串中不是[ATGC]的字符替换为其他字符,让我们说“A”,同时获取已被替换字符的位置;

我试过了:

while ($str=~/[^ATGC]/ig)
{
  $pos = pos($str);
  substr($str, $pos-1,1) = "A";
}

但速度不快。

有谁知道更好的方法吗?

5 个答案:

答案 0 :(得分:6)

正则表达式也可以替换匹配。

$str =~ s/X/A/g;

如果你只做一个字符,你甚至可以使用tr运算符。

$str =~ tr/X/A/g;

甚至可能更快。

答案 1 :(得分:5)

您可以使用search and replace直接使用正则表达式执行替换:

$str =~ s/X/A/ig;

答案 2 :(得分:3)

如有疑问,Benchmark

use strict;
use warnings;
use v5.14;

use Benchmark qw(cmpthese);

my @l = qw(A T G C X);
my $BAR;
$BAR .= $l[rand(@l)] for 1..10000;

cmpthese(-1, {
    substr          => sub { my $str = $BAR; 
                         while ($str=~/X/ig) {
                             my $pos = pos($str);
                             substr($str, $pos-1,1) = "A";
                         } return $str; },
    substitution    => sub { my $str = $BAR; $str =~ s/X/A/ig;  return $str; },
    transliteration => sub { my $str = $BAR; $str =~ tr/xX/aA/; return $str; }});

<强>结果:

                   Rate          substr    substitution transliteration
substr           55.1/s              --            -98%           -100%
substitution     2496/s           4433%              --            -93%
transliteration 35134/s          63719%           1308%              --

正如我们从结果中看到的,对于这个特定的字符串和正则表达式,substr方法确实非常慢,速度为每秒55。使用替换的速度大约快45倍,但这比音译速度快了600倍。

因此,在这种情况下,音译似乎是最快的。这是有道理的,因为它是迄今为止最简单的潜艇。

答案 3 :(得分:2)

如果您只想替换输入字符串中的“X”字符,则可以采用音译方式,并显着提高您的速度。

记录替换字符的位置有点额外的皱纹。我建议如下:

my $huge_string = "GATTACAXX.......";
my $length = length($huge_string);
my $i = 0;

my $output_string;
my @x_positions;

while ($i < $length) {
    my $curr_char = substr($huge_string, $i, 1);
    if ($curr_char eq "X") {
        push (@x_positions, $i);
        $output_string .= "A"; # or G, C, T, etc.
    } else {
        $output_string .= $curr_char;
    }
    $i++;
}

# do something with $output_string and @x_positions...

我在一个> 1,000,000个字符的测试字符串上运行它,它在不到一秒的时间内完成,而原始代码片段的运行时间约为3分钟。

希望有所帮助。

答案 4 :(得分:1)

如果您只是将一个字符替换为另一个字符(逐个字符串或逐个字符串!!!),则音译速度更快:$str =~ tr/X/A/; 如果您需要复杂的正则表达式模式,请考虑使用re::engine::RE2Google RE2 engine的Perl绑定。请注意,复杂正则表达式只会更快。