Regexp::Exhaustive - Find all possible matches, including backtracked and overlapping, of a pattern against a string
use Regexp::Exhaustive qw/ exhaustive /; print "Subsets:\n"; print "$_\n" for exhaustive('abc' => qr/.+/); print "\n"; print "Overlapping matching:\n"; print "$_\n" for exhaustive('abc' => qr/(?>.+)/); print "\n"; print "Heads and tails:\n"; print "@$_\n" for exhaustive('abcde' => qr/^(.+?)(.+)\z/); print "\n"; print "Triplets:\n"; print "@$_\n" for exhaustive('abcde' => qr/(.)(.)(.)/); print "\n"; print "Binary count:\n"; print map(length, @$_), "\n" for exhaustive('111', qr/^(.??)(.??)(.??)/); __END__ Subsets: abc ab a bc b c Overlapping matching: abc bc c Heads and tails: a bcde ab cde abc de abcd e Triplets: a b c b c d c d e Binary count: 000 001 010 011 100 101 110 111
This module does an exhaustive match of a pattern against a string. That means that it will match all ways possible, including all backtracked and overlapping matches.
It works a lot like the familiar m//g regarding return values.
m//g
Beware that exhaustive matching may generate a very large number of matches. If you only need overlapping matches that's easily achieved. Overlapping matching has a maximum number of matches being the length of the string plus one.
This is an initial release, and some things may change for the next version. If you feel something is missing or poorly designed, now is the time to voice your opinion.
Nothing is exported by default. The :ALL tag exports everything that can be exported.
:ALL
exhaustive(STRING => qr/PATTERN/)
Exhaustively generates and returns all matches in list context. Returns the number of matches in scalar context.
If the pattern doesn't contain any capturing subpatterns, the matched string (equivalent of $&) is returned. If only one capturing subpattern is seen then $1 is returned. Otherwise $1, $2, etc is returned grouped using array references.
$&
$1
$2
This is like m//g in list context, except m//g returns all capturing subpatterns as a flat list.
This method does not interact with pos($str) and can be safely intermixed with other match operations against the string.
pos($str)
Worthy to note is that it's much more efficient to use qr/(.)/ than qr/./, i.e. making direct use of $1 instead of having exhaustive calculate $&.
qr/(.)/
qr/./
exhaustive
exhaustive(STRING => qr/PATTERN/, qw[ $1 $2 @- $^R ... ])
Optionally, you can specify which variables to return. Arrays and hashes will end up as references in the return list.
If two or more variables are specified they will be grouped using array references.
my @matches = exhaustive('abc' => qr/(a)|(b)/, qw/ $1 $2 $+ /); for (@matches) { print join("\t", map { defined() ? $_ : 'undef' } @$_) . "\n"; } __END__ a undef a undef b b
Supported variables:
Punctuation: English alias: $<*digits*> $` $PREMATCH $& $MATCH $' $POSTMATCH $+ $LAST_PAREN_MATCH $^N @- @LAST_MATCH_START @+ @LAST_MATCH_END %- %+ $^R $LAST_REGEXP_CODE_RESULT
Using $`, $&, and $' with exhaustive doesn't impose the performance penalty that those variables otherwise impose. However, they're usually slower to use than rewriting the pattern to use capturing subpatterns. In particular, $& is often easy to avoid by just adding an outer capturing parenthesis and using $1 instead.
$`
$'
overlapping(STRING => qr/PATTERN/)
If this function would exist, but it doesn't, it would be like global match but try to match from every position of the string. It's like an exhaustive match that doesn't backtrack inside the pattern.
This function doesn't exist because it isn't needed. Instead use
exhaustive(STRING => qr/(?>PATTERN)/)
i.e. wrap the pattern with the (?>...) assertion. This will lock the match once the pattern has matched, forcing the regex engine to skip behind the pattern when backtracking, thus moving forward on the string for the next match.
(?>...)
Using
STRING =~ /(?=PATTERN)/g
will be faster, but has three key differences: (1) assumes pos() is undefined, (2) undefines pos(), and (3) returns all captured subpatterns as a flat list. Note that saving away pos() and then restoring it may cause certain global matches to loop infinitely.
pos()
$_ = 'foo'; while (/.??/g) { print pos(); pos() = pos(); # Not really doing anything, or is it? }
This will loop forever.
(W|uninitialized) The string given to exhaustive was not defined.
(F) Self-explanatory.
(F) An argument for a regex variable name was not defined.
(F) You supplied a string that didn't look like a known regex variable. See exhaustive for supported variables.
See "SYNOPSIS" for more examples.
A commonly known snippet of regex can be used to find out if an integer is a prime number or not.
sub is_prime { my ($n) = @_; my $str = '.' x $n; return $str =~ /^(?:..+)\1+$/ ? 0 : 1; } print '9 is prime: ', is_prime(9), "\n"; print '11 is prime: ', is_prime(11), "\n"; __END__ 9 is prime: 0 11 is prime: 1
Equally simple is it, with Regexp::Exhaustive, to find out not only if it's a prime number, but which its divisors are.
Regexp::Exhaustive
use Regexp::Exhaustive 'exhaustive'; sub divisors { my ($i) = @_; return map length, exhaustive('.' x $i => qr/^(.+?)\1*$/); } print "$_\n" for divisors(12); __END__ 1 2 3 4 6 12
Set::CrossProduct gives you the cross product of a set, and that's the good way of doing just that. But as an example, here's how you can find all possible combinations of two four-sided dice using Regexp::Exhaustive. To illustrate the difference between greedy and non-greedy matches I let the second die be in reversed order.
use Regexp::Exhaustive 'exhaustive'; my $sides = '1234'; my @sets = exhaustive( "$sides\n$sides" => qr/^.*?(.).*\n.*(.)/ ); print "@$_\n" for @sets; __END__ 1 4 1 3 1 2 1 1 2 4 2 3 2 2 2 1 3 4 3 3 3 2 3 1 4 4 4 3 4 2 4 1
Using Regexp::Exhaustive you can generate all values of a certain digit length using an n-ary count. This is demonstrated for binary numbers with a length of three. (The length is assumed to be greater than one.)
use Regexp::Exhaustive 'exhaustive'; sub all_values { my ($n, @base) = @_; my $str = (join('', @base) . "\n") x $n; my $re = qr/.*?(.).*\n/ x $n; return map { join '', @$_ } exhaustive($str, qr/^$re/); } print "$_\n" for all_values(3, qw/ 0 1 /); __END__ 000 001 010 011 100 101 110 111
This module uses the experimental (?{ ... }) assertion. Thus this module is as experimental as that assertion.
(?{ ... })
Thanks to Mike Rosulek for giving useful feedback and suggestions.
Johan Lodin <lodin@cpan.org>
Copyright 2005-2007 Johan Lodin. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
perlre for regular expressions.
perlvar for the special variables.
To install Regexp::Exhaustive, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Regexp::Exhaustive
CPAN shell
perl -MCPAN -e shell install Regexp::Exhaustive
For more information on module installation, please visit the detailed CPAN module installation guide.