Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

All, I can do an OR (alternate) match in Regex using pipe symbol. Here either scan or print can be present in the string.
e.g. m/(scan|print)/

But how to do an AND match. Where both scan and print should be present in the string.
e.g. m/((scan.*?print)|(print.*?scan))/

Agree. It is ugly and more the combination it gets even more ugly. There should be a be an elegant way of doing this. Thanks for your help.

Replies are listed 'Best First'.
Re: Multiple Match (Sort of AND)
by BrowserUk (Patriarch) on Apr 25, 2010 at 17:08 UTC

    Generating a regex is easier than hand coding.

    And far easier than hand-coding re and re and re and ... once you get beyond half a dozen or so.

    This generates two res, one just tests if all the elements are present. The other both tests for them, and captures those that are matched:

    #! perl -slw use strict; my $re = join'', map{ "(?=^.*$_)" } qw[ scan print rinse repeat ]; my $re2 = join'', map{ "(?=^.*($_))?" } qw[ scan print rinse repeat ]; chomp( my @tests = <DATA> ); print "Just test"; for( @tests ){ printf "$_: %s\n", $_ =~ $re ? 'matched' : 'no match'; } print "\nTest and what"; for( @tests ){ my @matched = grep defined, $_ =~ $re2; printf "$_: %s\n", @matched ? "matched: [@matched]" : 'no match'; } __DATA__ scan and print and rinse and repeat print and scan and rinse and repeat print and scan and rinse print fred

    Output:

    C:\test>junk44 Just test scan and print and rinse and repeat: matched print and scan and rinse and repeat: matched print and scan and rinse: no match print: no match fred: no match Test and what scan and print and rinse and repeat: matched: [scan print rinse repeat +] print and scan and rinse and repeat: matched: [scan print rinse repeat +] print and scan and rinse: matched: [scan print rinse] print: matched: [print] fred: no match

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Multiple Match (Sort of AND)
by wfsp (Abbot) on Apr 25, 2010 at 15:42 UTC
    What ww said. :-)

    But even that could get ugly. Perhaps put all your combinations in an array and loop over them. You then have a chance to see which element(s) were missing.

    #! /usr/bin/perl use strict; use warnings; my @combinations = qw{ scan print rinse repeat }; my @test_strings = do{local $\;<DATA>}; chomp @test_strings; for my $string (@test_strings){ my @misses; for my $ele (@combinations){ next if $string =~ /\Q$ele\E/; push @misses, $ele; } print $string, q{ -> }; if (@misses){ print qq{no matches for: @misses\n}; } else{ print qq{all matched\n}; } } __DATA__ scan and print and rinse and repeat print and scan and rinse and repeat print and scan and rinse print
    scan and print and rinse and repeat -> all matched print and scan and rinse and repeat -> all matched print and scan and rinse -> no matches for: repeat print -> no matches for: scan rinse repeat
Re: Multiple Match (Sort of AND)
by ww (Archbishop) on Apr 25, 2010 at 15:29 UTC
    Take your AND out of your regex; use it to connect multiple regexen.
      Please note that /(PAT1.*PAT2)|(PAT2.*PAT1)/ and /PAT1/ and /PAT2/ are not equivalent. The latter will match if PAT1 and PAT2 can overlap, while the former will only match non-overlapping patterns. For instance,
      $_ = "foof"; /(foo.*oof)|(oof.*foo)/;
      doesn't match, but
      $_ = "foof"; /foo/ and /oof/
      does.

      Note also that using multiple regexes cannot always be done. Think functions taking regexes are argument (split!), or patterns stored in configuration files.

Re: Multiple Match (Sort of AND)
by samarzone (Pilgrim) on Apr 26, 2010 at 05:42 UTC

    I came up with following -

    perl -e '$a = "abc print pqr scan xyz"; print "matched\n" if($a =~ /(? +=.*(?=scan))(?=.*(?=print))/)' matched
Re: Multiple Match (Sort of AND)
by Anonymous Monk on Apr 25, 2010 at 17:23 UTC
    Thanks a lot for all the answers.
Re: Multiple Match (Sort of AND)
by Marshall (Canon) on Apr 27, 2010 at 19:18 UTC
    The simple way is to see if each individual term is in the string and then "and" the true/falseness of those regex'es together.
    if (m/scan/ && m/print/){..both scan and print found..}