regular expression like AND match

Discussion in 'Perl Misc' started by ikeon, Dec 23, 2008.

  1. ikeon

    ikeon Guest

    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,
     
    ikeon, Dec 23, 2008
    #1
    1. Advertising

  2. ikeon <> writes:

    > 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
     
    Peter Makholm, Dec 23, 2008
    #2
    1. Advertising

  3. ikeon

    Mirco Wahab Guest

    ikeon wrote:
    > 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.
     
    Mirco Wahab, Dec 23, 2008
    #3
  4. ikeon <> wrote:
    >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ürgen Exner, Dec 23, 2008
    #4
  5. ikeon

    Jim Gibson Guest

    In article
    <>,
    ikeon <> wrote:

    > 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.

    --
    Jim Gibson
     
    Jim Gibson, Dec 23, 2008
    #5
  6. Mirco Wahab <> writes:

    > 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
     
    Peter Makholm, Dec 24, 2008
    #6
  7. ikeon

    Guest

    On Tue, 23 Dec 2008 06:16:55 -0800 (PST), ikeon <> wrote:

    >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
     
    , Dec 24, 2008
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. championsleeper
    Replies:
    6
    Views:
    1,050
    championsleeper
    Apr 6, 2004
  2. Liang
    Replies:
    2
    Views:
    1,767
  3. VSK
    Replies:
    2
    Views:
    2,379
  4. Replies:
    4
    Views:
    749
  5. Azalar ---
    Replies:
    6
    Views:
    270
    Robert Klemme
    Sep 8, 2008
Loading...

Share This Page