일부 시작 위치에서 문자열에서 패턴의 첫 번째 발생을 어떻게 찾을 수 있습니까?

StackOverflow https://stackoverflow.com/questions/120071

  •  02-07-2019
  •  | 
  •  

문제

임의의 길이가 많고 위치 P0에서 시작하여 세 가지 3 글자 패턴 중 하나의 첫 번째 발생을 찾아야합니다.

문자열에는 글자 만 포함되어 있다고 가정합니다. 위치 P0에서 시작하여 'AAA'또는 'BBB'또는 'CCC'가 처음 발생할 때까지 트리플렛에서 뛰어 내리는 트리플렛 수를 찾아야합니다.

이것은 재생을 사용하는 것도 가능합니까?

도움이 되었습니까?

해결책

Moritz는 이것이 Regex보다 빠를 수 있다고 말합니다. 조금 느려도 오전 5시에 이해하기가 더 쉽습니다. :)

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

while( $pos < length $string )    
    {  
    print "Checking $pos\n";  

    if( substr( $string, $pos, $length ) =~ /$regex/ )
        {
        print "Found $1 at $pos\n";
        last;
        }

    $pos += $length;
    }

다른 팁

$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)/;

당신은 실제로 regexes로 계산할 수는 없지만 다음과 같은 일을 할 수 있습니다.

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 ()와 포장 ()을 사용하여 트리플으로 나누고 트리플을 for-loop로 걸어가는 것이 조금 더 빠르다고 생각합니다.

(편집 : lenght ()가 아닌 길이 () ;-)

이것의 주요 부분은 분할 /(...)/입니다. 그러나이 결국, 당신은 당신의 위치와 발생 데이터를 갖게 될 것입니다.

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};
}

또는 REGEX의 간단한 계산을 위해 (실험을 사용합니다 (?? {}).

my ( $count, %count );
my $data_string      
    = 'fjeidoaaaivtrxxcccfznaaauitbbbfzjasdjfncccftjtjqznnjgjaaajeitjgbbblafjan'
    ;
$data_string =~ m/(aaa|bbb|ccc)(??{ $count++; $count{$^N}++ })/g;

속도가 심각한 관심사 인 경우, 3 줄이 무엇인지에 따라 트리를 만들어 정말 멋진 일을 할 수 있습니다 (예 : AHO-CORASICK 알고리즘 또는 이와 유사한).

가능한 모든 상태에 대한 맵이 가능합니다 (예 : 상태) [0] [ 'a'] = 0 문자열이 'a'로 시작되지 않으면.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top