كيف يمكنني العثور على التواجد الأول للنمط في سلسلة من موضع البداية؟

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

  •  02-07-2019
  •  | 
  •  

سؤال

لدي سلسلة ذات طول عشوائي، وبدءًا من الموضع p0، أحتاج إلى العثور على أول ظهور لأحد الأنماط الثلاثة المكونة من 3 أحرف.

افترض أن السلسلة تحتوي على أحرف فقط.أحتاج إلى العثور على عدد التوائم الثلاثة بدءًا من الموضع p0 والقفز للأمام في ثلاثة توائم حتى ظهور أول إما "aaa" أو "bbb" أو "ccc".

هل هذا ممكن حتى باستخدام 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)/;

لا يمكنك الاعتماد حقًا باستخدام التعابير المنطقية، ولكن يمكنك القيام بشيء مثل هذا:

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-loop.

(يحرر:طوله () وليس طوله () ;-)

الجزء الرئيسي من هذا مقسم /(...)/.ولكن في نهاية هذا، سيكون لديك مواقعك وبيانات الحدوث.

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;

إذا كانت السرعة مصدر قلق جدي، فيمكنك، اعتمادًا على ماهية الأوتار الثلاثة، أن تصبح خياليًا حقًا من خلال إنشاء شجرة (على سبيل المثال.خوارزمية Aho-Corasick أو ما شابه).

خريطة لكل ولاية ممكنة ممكنة، على سبيل المثال.الحالة [0] ['a'] = 0 إذا لم تكن هناك سلاسل تبدأ بـ "a".

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top