http://www.perlmonks.org?node_id=2150

vroom has asked for the wisdom of the Perl Monks concerning the following question: (regular expressions)

How do I find the Nth occurrence of a pattern?

Originally posted as a Categorized Question.

  • Comment on How do I find the Nth occurrence of a pattern?

Replies are listed 'Best First'.
Re: How do I find the Nth occurrence of a pattern?
by Roy Johnson (Monsignor) on Oct 28, 2003 at 20:53 UTC
    A recent discussion found this to be the fastest way, and it's pretty slick:
    $_='abcabbcabbbbcabcabbcab'; my $n = 3; ## Find the $nth occurrence my $pat = qr/ab+/; ## of this pattern my ($NthMatch) = /(?:.*?($pat)){$n}/; print "Match #$n looks like $NthMatch\n";
    The regex is: find the pattern (optionally preceded by something that isn't the pattern) n times. The pattern is in parens, so the final match will be returned.
Re: How do I find the Nth occurrence of a pattern?
by maverick (Curate) on Jun 28, 2000 at 00:15 UTC
    you could use =~ in array context like:
    $string = "12 34 56 78 90 98 76 54 32 10"; (@matches) = ($string =~ /(\d+)/g); print "fifth match is $matches[4]\n"; print "eigth match is $matches[7]\n";

    /\/\averick
Re: How do I find the Nth occurrence of a pattern?
by vroom (His Eminence) on Jan 18, 2000 at 23:44 UTC
    Use the /g (global) to find all occurrences in a string. Place the matching statement within a while loop and count until you get to the wanted number.
    $n=5; #want the 5th occurrence of a group of 5 numbers $count=0; while(/(\d{5})/g){ if(++$count==$n){ print "The $n\th occurrence was $1\n"; } }
Re: How do I find the Nth occurrence of a pattern?
by eak (Monk) on Aug 06, 2000 at 08:29 UTC
    Here is my monkified version of the nth_iter subroutine. You gotta love map{}.
    #!/usr/bin/perl -w my @string = (34, 56, 78, 90, 98, 76, 54, 32, 10, 12, 13, 16, 19, 20, +10, 56); sub nth_iter{ my ($item, $n, $list) = @_; ( map { $string[$_] == $item ? $_ : (); } 0..$#string )[--$n] or -1; } print nth_iter(78, 1, \@string);
      I have to correct my code. I passed in a reference and never used it :(.
      #!/usr/bin/perl -w my @string = (34, 56, 78, 90, 98, 76, 54, 32, 10, 12, 13, 16, 19, 20, +10, 56); sub nth_iter{ my ($item, $n, $list) = @_; ( map { $list->[$_] == $item ? $_ : (); } 0..$#$list )[--$n] or -1 +; } print nth_iter(78, 1, \@string);
        Now using grep...speeed!!
        #!/usr/bin/perl -w my @string = (34, 56, 78, 90, 98, 76, 54, 32, 10, 12, 13, 16, 19, 20, +10, 56); sub nth_iter{ my ($item, $n, $list) = @_; ( grep $list->[$_] == $item, 0..$#$list )[--$n] or -1; } print nth_iter(10, 3, \@string);
Re: How do I find the Nth occurrence of a pattern?
by poolpi (Hermit) on Oct 26, 2012 at 14:32 UTC

    With split

    my $string = "12 34 56 78 90 98 76 54 32 10"; my $n = 3; print+ (split( /[^\d+]/, $string))[$n-1]; # output => 56 my $string ='abcabbcabbbbcabcabbcab'; my $n = 3; print+ (split( /[^(?:ab+)]/, $string ))[$n-1]; # output => abbbb
Re: How do I find the Nth occurrence of a pattern?
by cLive ;-) (Prior) on Mar 30, 2001 at 10:53 UTC
    Haven't tested this, but liked the idea.... :)
    my $n = whatever... my $i=0; while ( ($string =~ /PATTERN/g) && ($i < $n ) ) { $i++; } my $NthMatch = $1;
Re: How do I find the Nth occurrence of a pattern?
by Anonymous Monk on Aug 06, 2000 at 07:27 UTC
    Here is a way to do this. This is more C than perl. I'd love for a monk to translate it. This defines a function that takes: the item to find, the teration to locate, an arry to search This returns the array index of the nth element. You get a -1 if none found.
    @string = qw(34, 56, 78, 90, 98, 76, 54, 32, 10, 12, 13, 16, 19, 20, 1 +0, 56); sub nth_iter { my($item, $n, @list) = @_; $i = -1; $match = 0; $len = @list; while ($i++ < $len) { if($list[$i] == $item) { $match++; if ($match == $n) { last; } } } if ($match != $n) { $i = -1; } return $i; } print nth_iter(78, 1, @string);
    Rock on! -Ty
Re: How do I find the Nth occurrence of a pattern?
by Anonymous Monk on May 09, 2003 at 16:17 UTC
    C#
    Regex reg = new Regex( matchExpression ); MatchCollection matches = reg.Matches( value ); if ( matches.Count >= Nth occurrence ) { matches[n].Value); }

    Originally posted as a Categorized Answer.