regular expression like AND match

I

ikeon

The case is that I need to search for a couple of strings in a line. I
don't know the order that they will be matched and I need them all to
be matched.
like if (string1|string2|string3) can find one of the strings (OR) , I
need it to match all of the strings (like AND) and again - I don't
know the order that they will appear.
I know how to do it if I will check the line 3 times in some loop, but
I need to know if it can be done in one regular expression.

Thanks,
 
P

Peter Makholm

ikeon said:
I know how to do it if I will check the line 3 times in some loop, but
I need to know if it can be done in one regular expression.

Yes, it can be done in a single regular expression, but why do you
need to do it in a single regular expression?

It's quite easy by using the correct look-around assertion, but I
guess it will be neither faster nor more maintainable than doing
something like:

/pat1/ && /pat2/ && /pat3/


//Makholm
 
M

Mirco Wahab

ikeon said:
The case is that I need to search for a couple of strings in a line. I
don't know the order that they will be matched and I need them all to
be matched.
like if (string1|string2|string3) can find one of the strings (OR) , I
need it to match all of the strings (like AND) and again - I don't
know the order that they will appear.
I know how to do it if I will check the line 3 times in some loop, but
I need to know if it can be done in one regular expression.

This is nontrivial (imho) but can be done using
code assertions. The magic lies in setting a signal
denotig a specified hit during the match, e.g.
setting a bit in a word for each string matched.

Example:

...

# what to find
my @strings = qw'string1 string2 string3';

# where to find
my @lines = ('first line string1 ',
'second line string1 string2 ',
'third line string1 string2 string3 ');
#expect: only line #3 shall match

# make regex out of the search strings above (note the 'bts' thing)
my $cnt = 0;
my $reg = join '|', map $_.'(?{$bts|='.(1<<$cnt++).'})', @strings;

# apply regex to the lines
foreach my $line (@lines) {

our $bts = 0; # used within the regex engine
use re 'eval';
# ignore line unless the 'bits' 1,2,3 are in place
next unless () = $line=~/$reg/g, $bts == 7;

# we got one, do something ($bts was 7)
print "$line\n"

}

...

Regards

M.
 
J

Jürgen Exner

ikeon said:
The case is that I need to search for a couple of strings in a line. I
don't know the order that they will be matched and I need them all to
be matched.
like if (string1|string2|string3) can find one of the strings (OR) , I
need it to match all of the strings (like AND) and again - I don't
know the order that they will appear.
I know how to do it if I will check the line 3 times in some loop, but
I need to know if it can be done in one regular expression.

Is there anything wrong with something like

if (/string1/ or /string2/ or /string3/) {
...
}

resp.
if (/string1/ and /string2/ and /string3/) {
...
}

jue
 
J

Jim Gibson

ikeon said:
The case is that I need to search for a couple of strings in a line. I
don't know the order that they will be matched and I need them all to
be matched.
like if (string1|string2|string3) can find one of the strings (OR) , I
need it to match all of the strings (like AND) and again - I don't
know the order that they will appear.
I know how to do it if I will check the line 3 times in some loop, but
I need to know if it can be done in one regular expression.

In scalar context, 'grep {BLOCK} LIST' will return the number of times
BLOCK evaluates to true for the members of LIST. So you can put your
strings to be found in an array and do something like:

my @strings = qw( string1 string2 string3 );
my $string = '... string3 ... string1 ... string2 ...';
my $n = grep { $string =~ /$_/ } @strings;
if( $n == @strings ) {
print "All strings found\n";
}

This method has the advantage over the

if( /string1/ && /string2/ && /string3/ ) { ... }

method in that you can vary the number of strings to be matched without
changing the matching code.
 
P

Peter Makholm

Mirco Wahab said:
my $reg = join '|', map $_.'(?{$bts|='.(1<<$cnt++).'})', @strings;

Wow. Simple look ahead assertions would du just fine. Don't turn it
into rocket science just because the single regexp requirement is
silly.

//Makholm
 
S

sln

The case is that I need to search for a couple of strings in a line. I
don't know the order that they will be matched and I need them all to
be matched.
like if (string1|string2|string3) can find one of the strings (OR) , I
need it to match all of the strings (like AND) and again - I don't
know the order that they will appear.
I know how to do it if I will check the line 3 times in some loop, but
I need to know if it can be done in one regular expression.

Thanks,

Alot of good suggestions already.
I guess you could do something like this as well.

sln

---------------------------------------------------
use strict;
use warnings;


my @strings = ("find this", "that too", "and other");
my $patrx = join '|', @strings;
$patrx = qr/$patrx/;

my $fpos = tell(DATA);

## To match all or some -
while (<DATA>)
{
chomp; next if (!length);
my %seen = ();

if (s/($patrx)/$seen{$1}=$1/eg && (keys %seen) == @strings)
{
# matched all
my $found = join ',', keys %seen;
print "found ALL: '$found'\n\tin '$_'\n";
}
else
{
# matched some or none
my $found = join ',', keys %seen;
print "found ".(keys %seen)."/".@strings.": '$found'\n\t in '$_'\n";
}
}

print "====================\n";
seek(DATA, $fpos, 0);

## To match any -
while (<DATA>)
{
chomp; next if (!length);

if (/($patrx)/)
{
# matched one
print "found '$1'\n\t in '$_'\n";
}
}


__DATA__

first line string1
second line string1 string2 find this
third line string1 string2 string3
find this", "that too", "and other
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top