#!/usr/bin/perl use warnings; use strict; use Benchmark qw/:all/; sub salva { my($string,$char,$n) = @_; my $pat = "[^$char]*$char" x $n; my $where = -1; $string =~ /^($pat)/ and $where = length($1) - 1; return $where; } { my %hash; sub mickeyn { my ($string,$c,$n) = @_; return -1 if $n < 1; return $hash{$string}{$c}[$n-1] || -1 if exists $hash{$string}; my @split = split //, $string; my @positions = map { [$split[$_], $_] } 0 .. $#split; undef @split; foreach (@positions){ push @{$hash{$string}{$_->[0]}}, $_->[1]; } undef @positions ; return $hash{$string}{$c}[$n-1] || -1; } } sub RoyJohnson { my ($str,$char,$n) = @_; $str =~ /(?:.*?$char){$n}/g; return pos($str)-1 if defined pos($str); return -1; } sub find_nth { my ($s,$c,$n) = @_; my $pos = -1; while ($n--) { $pos = index($s,$c,$pos+1); return -1 if $pos == -1; } return $pos; } sub rule { my $s = shift; my $l = int(length($s)/10)+1; my $r1 = '0123456789' x $l; my $r2 = ' ' x $l; $r1 = substr($r1,0,length($s)); substr($r2,$_*10,1) = $_ for 1..length($s)/10; return "$r2\n$r1\n"; } sub test { my ($str,$c) = @_; print rule($str), "$str\n"; print "($c,$_): ", join(" ", find_nth($str,$c,$_), salva($str,$c,$_), mickeyn($str,$c,$_), RoyJohnson($str,$c,$_) ),"\n" for -1..10; } my $str="Now is the time for all good men to come to the aid of their country"; my $n = 5; my $c = "o"; # test($str,$c); exit; my $time = shift || -5; cmpthese($time, { duff => sub { find_nth($str,$c,$_) for -1..10; }, salva => sub { salva($str,$c,$_) for -1..10; }, mickeyn => sub { mickeyn($str,$c,$_) for -1..10; }, RoyJohnson => sub { RoyJohnson($str,$c,$_) for -1..10; }, }); my @strings = ( "Now is the time for all good men to come to the aid of their country", "Four score and seven years ago our forefathers brought forth unto this country", "How to write an efficient Perl function to return the position of the nth occurance of a specified character within a string?", "The rain in spain lies mainly upon the plain", "a" x 200, "a" x 200 . "ooo", "o" x 200, ); cmpthese($time, { duff => sub { find_nth($_,$c,3) for @strings; }, salva => sub { salva($_,$c,3) for @strings; }, mickeyn => sub { mickeyn($_,$c,3) for @strings; }, RoyJohnson => sub { RoyJohnson($_,$c,3) for @strings; }, });