6

我有一个任意长度的字符串,从位置 p0 开始,我需要找到三个 3 字母模式之一的第一次出现。

假设字符串只包含字母。我需要找到从位置 p0 开始并以三元组形式向前跳跃的三元组计数,直到第一次出现“aaa”或“bbb”或“ccc”。

这甚至可能仅使用正则表达式吗?

4

5 回答 5

12
$string=~/^   # from the start of the string
            (?:.{$p0}) # skip (don't capture) "$p0" occurrences of any character
            (?:...)*?  # skip 3 characters at a time,
                       # as few times as possible (non-greedy)
            (aaa|bbb|ccc) # capture aaa or bbb or ccc as $1
         /x;

(假设 p0 从 0 开始)。

当然,在字符串上使用 substr 来跳过可能更有效:

substr($string, $p0)=~/^(?:...)*?(aaa|bbb|ccc)/;
于 2008-09-23T09:44:27.223 回答
12

Moritz 说这可能比正则表达式更快。哪怕慢一点,早上5点还是比较容易理解的。:)

             #0123456789.123456789.123456789。  
我的 $string = "alsdhfaaasccclaaaagalkfgblkgbklfs";  
我的 $pos = 9;  
我的 $length = 3;  
我的 $regex = qr/^(aaa|bbb|ccc)/;

而( $pos < 长度 $string )    
    {  
    print "检查 $pos\n";  

    if( substr( $string, $pos, $length ) =~ /$regex/ )
        {
        print "在 $pos\n 找到 $1";
        最后的;
        }

    $pos += $长度;
    }
于 2008-09-23T10:19:50.853 回答
9

您不能真正使用正则表达式,但您可以执行以下操作:

pos $string = $start_from;
$string =~ m/\G         # anchor to previous pos()
            ((?:...)*?) # capture everything up to the match
            (aaa|bbb|ccc)
            /xs  or die "No match"
my $result = length($1) / 3;

但我认为使用 substr() 和 unpack() 拆分为三元组并在 for 循环中遍历三元组会更快一些。

(编辑:它是长度(),而不是长度();-)

于 2008-09-23T09:56:28.303 回答
0

主要部分是拆分/(...)/。但在此结束时,您将获得您的位置和发生数据。

my @expected_triplets = qw<aaa bbb ccc>;
my $data_string      
    = 'fjeidoaaaivtrxxcccfznaaauitbbbfzjasdjfncccftjtjqznnjgjaaajeitjgbbblafjan'
    ;
my $place          = 0;
my @triplets       = grep { length } split /(...)/, $data_string;
my %occurrence_for = map { $_, [] } @expected_triplets;
foreach my $i ( 0..@triplets ) {
    my $triplet = $triplets[$i];
    push( @{$occurrence_for{$triplet}}, $i ) if exists $occurrence_for{$triplet};
}

或者通过正则表达式进行简单计数(它使用实验性 (??{}))

my ( $count, %count );
my $data_string      
    = 'fjeidoaaaivtrxxcccfznaaauitbbbfzjasdjfncccftjtjqznnjgjaaajeitjgbbblafjan'
    ;
$data_string =~ m/(aaa|bbb|ccc)(??{ $count++; $count{$^N}++ })/g;
于 2008-09-23T18:24:27.427 回答
0

如果速度是一个严重的问题,您可以根据 3 个字符串的内容,通过创建一棵树(例如 Aho-Corasick 算法或类似算法)来获得真正的幻想。

每个可能状态的映射都是可能的,例如,如果没有字符串以 'a' 开头,则 state[0]['a'] = 0。

于 2008-11-07T21:16:04.580 回答