#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use constant MIN => 2; use Benchmark qw/:all :hireswallclock/; my $str='aabcdabcabcecdecd'; sub blazar { local $_=shift; my $l=length; my %count; for my $off (0..$l-1) { for my $len (MIN .. $l-$off) { my $s=substr $_, $off, $len; $count{ $s } ||= ()= /$s/g; } $count{$_} == 1 and delete $count{$_} for keys %count; } \%count; } sub oha { my $s=shift; my %saw; while($s =~ /(..+)(?=.*?\1)/g) { for my $x (0..length $1) { @saw{ map {substr $1, $x, $_} $x+2..length $1 } = (); } } $saw{$_} =()= $s =~ /\Q$_/g for keys %saw; \%saw; } { my %count; sub count1 { my( $string) = @_; my $length = length( $string ); if ($length < MIN) { $count{$_} == 1 and delete $count{$_} for keys %count; return \%count; } for my $l (MIN..$length) { my $s = substr( $string, 0, $l ); $count{ $s } += 1; } count1( substr( $string, 1 ) ); } sub kramba { count1 shift; for (keys %count) { delete $count{$_} unless $count{$_} >= 2 and length($_) >= MIN; } \%count; } } sub ikegami { my $str = shift; local our %counts; $str =~ / (.{2,}) # or (.+) (?(?{ !$counts{$1} })(?=.*\1)) (?{ ++$counts{$1} }) (?!) /x; \%counts; } cmpthese 10_000 => { blazar => sub { blazar $str }, oha => sub { oha $str }, kramba => sub { kramba $str }, ikegami => sub { ikegami $str }, }; __END__ #### Rate blazar kramba ikegami oha blazar 405/s -- -77% -89% -89% kramba 1788/s 341% -- -52% -52% ikegami 3743/s 823% 109% -- -0% oha 3743/s 823% 109% 0% -- #### sub lodin { my $str = shift; local our %count; $str =~ / (.{2,}) (?(?{ $count{$1} }) (?!) ) .* \1 (?{ ($count{$1} ||= 1)++ }) (?!) /x; \%count; } #### sub kramba { my %count; my $count; $count = sub { my( $string) = @_; my $length = length( $string ); if ($length < MIN) { $count{$_} == 1 and delete $count{$_} for keys %count; return \%count; } for my $l (MIN..$length) { my $s = substr( $string, 0, $l ); $count{ $s } += 1; } $count->( substr( $string, 1 ) ); }; $count->(shift); for (keys %count) { delete $count{$_} unless $count{$_} >= 2 and length($_) >= MIN; } \%count; } #### Rate blazar kramba oha ikegami lodin blazar 577/s -- -72% -90% -91% -91% kramba 2045/s 254% -- -66% -67% -69% oha 6039/s 946% 195% -- -2% -9% ikegami 6154/s 966% 201% 2% -- -8% lodin 6667/s 1055% 226% 10% 8% --