|
Posted by Ben Bullock on June 18, 2008, 5:47 am
Please log in for more thread options
On Wed, 18 Jun 2008 00:06:12 -0700, viki wrote:
> How can I build regex that matches all characters of the string $STR
> in any order with .* added between any two characters: ?
> And without generating all N! transpositions (where N is length of
> $STR) ?
> Example.
> For $STR "abc", I want to match equivalent to:
> /(a.*b.*c)|(a.*c.*b)|(b.*a.*c)|(b.*c.*a)|(c.*a.*b)|(c.*b.*a)/
>
> Generating all transpositions is not feasible for larger legths of
> $STR.
> /[abc].*[abc].*[abc]/ is easy and fast but gives false positives.
> What is good solution ?
I don't think a single regular expression can do that, because there is
some logic involved which doesn't fit the regular expression mentality -
you have to work out what the first character matched was, then change
the second character to match depending on that, and so on.
I would use the easy and fast method and then remove the false positives
by checking that the matched string contained all n characters, perhaps
using s or tr n times and dropping out of the loop if one of my
substitutions failed.
The following seems to work, although I haven't tested it extensively:
#!/usr/local/bin/perl
use warnings;
use strict;
sub matches
{
my ($s, $STR) = @_;
my %chars = map {$_ => 1} split ('', $STR);
my @chars = sort keys %chars;
my $anychar = join '', @chars;
my $matchany = join '.*',map "[$anychar]", @chars; # there's a better
way
if ($s =~ /$matchany/) {
my $copy = $s;
for my $c (@chars) {
return unless $copy =~ s/$c//g;
}
return 1;
}
return;
}
print "OK\n" if (matches('naninuneno','aeiou'));
print "OK\n" if (matches('naninunene','aeiou'));
|