<?xml version="1.0" encoding="windows-1252"?>
<node id="1005279" title="Re: Replace the nth occurence (testing and benchmarks)" created="2012-11-23 10:11:27" updated="2012-11-23 10:11:27">
<type id="11">
note</type>
<author id="757127">
tobyink</author>
<data>
<field name="doctext">
&lt;p&gt;Testing some of the existing answers...&lt;/p&gt;
&lt;readmore&gt;&lt;code&gt;
use v5.14;
use Test::More;
use Benchmark qw(:all);
use IO::Callback;

my @I;

package RNO {
	use Moo::Role;
	requires 'replace_nth_comma';
	
	my @gamut = (
		['a|b,c,d', 1, 'a,b,c,d'],
		['a,b|c,d', 2, 'a,b,c,d'],
		['a,b,c|d', 3, 'a,b,c,d'],
		['aa,bb,cc|dd', 3, 'aa,bb,cc,dd'],
		['|,,', 1, ',,,'],
		[',|,', 2, ',,,'],
		[',,|', 3, ',,,'],
		[',,,', 4, ',,,'],
	);
	
	sub test_count { scalar @gamut };
	
	sub test {
		my $class = shift;
		my $passes;
		for my $t (@gamut) {
			my ($target, @args) = @$t;
			my $result = $class-&gt;replace_nth_comma(@args);
			$passes += ::is($result, $target, "$class, target $target");
		}
		return $passes;
	}
	
	sub bench {
		my $class = shift;
		for my $count (0..63) {
			for my $t (@gamut) {
				my ($target, @args) = @$t;
				my $result = $class-&gt;replace_nth_comma(@args);
			}
		}
	}
}

# OP
package RNO_1004836 { 
	use Moo; with 'RNO';
	push @I, __PACKAGE__;
	sub replace_nth_comma {
		my (undef, $count, $str) = @_;
		$count++;  # off by one
		$str =~ s/(,)/--$count == 1 ? "|":$1/ge;
		return $str;
	}
}

# AnomalousMonk
package RNO_1004848 {
	use Moo; with 'RNO';
	push @I, __PACKAGE__;
	sub replace_nth_comma {
		my (undef, $count, $str) = @_;
		$count--;  # off by one, other way
		$str =~ s{ (?: , [^,]*){$count} \K , }{|}xms;
		return $str;
	}
}

# Kenosis
package RNO_1004858 {
	use Moo; with 'RNO';
	push @I, __PACKAGE__;
	sub replace_nth_comma {
		my (undef, $count, $str) = @_;
		$str =~ s/(,)/!--$count ? '|' : $1/ge;
		return $str;
	}
}

# choroba
package RNO_1004892 {
	use Moo; with 'RNO';
	push @I, __PACKAGE__;
	sub replace_nth_comma {
		my (undef, $count, $str) = @_;
		my $pos = '0E0'; # plain 0 means the string begins with $from
		while ($count-- and $pos &gt;= 0) {
			$pos = index $str, q(,), $pos eq '0E0' ? $pos : $pos + 1;
		}
		substr $str, $pos, 1, q(|) if $pos &gt; 0;
		return $str;
	}
}

# trizen
package RNO_1004895 {
	use Moo; with 'RNO';
	push @I, __PACKAGE__;
	sub replace_nth_comma {
		my (undef, $count, $str) = @_;
		while ($str =~ /,/g) {
			if (--$count == 0) {
				substr($str, $-[0], $+[0] - $-[0], '|');
				last;
			}
		}
		return $str;
	}
}

# grizzley
package RNO_1004906 {
	use Moo; with 'RNO';
	push @I, __PACKAGE__;
	sub replace_nth_comma {
		my (undef, $count, $str) = @_;
		$count--;  # off by one, other way
		$str =~ s/((,.*?){$count}),/$1|/;
		return $str;
	}
}

# LanX
package RNO_1005026 {
	use Moo; with 'RNO';
	push @I, __PACKAGE__;
	sub replace_nth_comma {
		no warnings;
		my (undef, $count, $str) = @_;
		my @str= split /,/, $str;
		$str = join( "," , @str[0..$count-1] ) . "|" . join ( "," , @str[$count..$#str] );
		return $str;
	}
}

my @passed;
for (@I) {
	push @passed, $_ if $_-&gt;test == $_-&gt;test_count;
}
done_testing;

select(IO::Callback-&gt;new('&gt;', sub {
	my $str = shift;
	$str =~ s/^/# /m;
	print STDOUT $str;
}));

say "Passed: @passed";

say "Benchmarks...";
cmpthese(-1, { map { my $class = $_; $class =&gt; sub { $class-&gt;bench } } @passed });
&lt;/code&gt;&lt;/readmore&gt;

&lt;p&gt;The fastest seems to be [id://1004895] by [trizen].&lt;/p&gt;
&lt;!-- Node text goes above. Div tags should contain sig only --&gt;
&lt;div class="pmsig"&gt;&lt;div class="pmsig-757127"&gt;
&lt;small&gt;&lt;small&gt;
&lt;tt&gt;perl -E'sub Monkey::do{say$_,for@_,do{($monkey=&amp;#x5B;caller(0)]-&gt;&amp;#x5B;3])=~s{::}{ }and$monkey}}"Monkey say"-&gt;Monkey::do'
&lt;/tt&gt;&lt;/small&gt;&lt;/small&gt;
&lt;/div&gt;&lt;/div&gt;</field>
<field name="root_node">
1004836</field>
<field name="parent_node">
1004836</field>
</data>
</node>
