Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Regular expression for two required words

by fsn (Friar)
on Nov 13, 2001 at 15:27 UTC ( #125027=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks. I am a humble seeker of your wisdom.

I need help writing a RegExp that matches when two words both are present in a string, but the order is unknown. Also, the words might or might not be next to eachother. The regexp should NOT match when only one word is present.

With nested if's it is trivial, but I would like to do it with a single regexp.

Example: If I have a file:

foo bar bar foo foo bar baz barbazfoo foofoobar

I wan't to match lines 1,2,6 and 7, but not 3 thorugh 5, using some match for foo and bar.

Any idea?

Edit Masem 2001-11-13 - Changed title from 'Regular expression and'

Replies are listed 'Best First'.
Re: Regular expression and
by davorg (Chancellor) on Nov 13, 2001 at 15:38 UTC

    Easiest solution is probably to use two regexes.

    while (<DATA>) { print if /foo/ && /bar/; } __DATA__ foo bar bar foo foo bar baz barbazfoo foofoobar

    "The first rule of Perl club is you don't talk about Perl club."

      or, if you don't know what the words are ahead of time:
      #!/usr/bin/perl -w use strict; my @approved = qw( foo bar); @approved = map { $_ = quotemeta $_; ### very important qr/$_/is; ## available in perl 6, not really needed } @approved; print "The approved list\n", join "\n", @approved; my $merex = join ' && ', map "/$_/", @approved; print "merex \n$merex\n\n"; if(@ARGV) { print "ARGV\n"; while(<DATA>) { print if eval $merex; } } else { while(<DATA>) { my $toprint = 0; for my $r(@approved) { $toprint++ if m/$r/; } print if $toprint == scalar @approved; } } __DATA__ foo bar bar foo foo bar baz barbazfoo foofoobar
      which yields:
      F:\dev>perl 3
      The approved list
      /(?si-xm:foo)/ && /(?si-xm:bar)/
      foo bar
      bar foo
      The approved list
      /(?si-xm:foo)/ && /(?si-xm:bar)/
      foo bar
      bar foo

      Chore List: 1 - buy more coffee 2 - re-impress upon davorg the importance of rule 1

      Disclaimer: Don't blame. It came from inside the void

      perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"

      ISTR Camel (2) also indicated this is faster, I'd add word boundaries to davorg's regex too, if the words can also occur within other words ;)


      Brother Frankus.


Re: Regular expression and
by andye (Curate) on Nov 13, 2001 at 15:44 UTC
    #!/usr/bin/perl -w use strict; while (<DATA>) { chomp; print; print /(?=.*foo)(?=.*bar)/s ? "\t match \n" : "\t no match \n" +; } __DATA__ foo bar bar foo foo bar baz barbazfoo foofoobar
    gives output:
    foo bar match bar foo match foo no match bar no match baz no match barbazfoo match foofoobar match


    Update re jeroenes's points below:
    1. I used /s to make '.' match any character, in case fsn's *real* strings weren't all in one line.
    2. Yes, or even print grep /(?=.*foo)(?=.*bar)/, <DATA> ; , but I wanted to print the failed matches too. Perhaps print map{ chomp; /(?=.*foo)(?=.*bar)/?"$_ yes \n":"$_ no \n"} <DATA> ;


      Two nitbits:
      1. You don't need the 's' modifier there, as the you already have the string in one line;
      2. This is a place to use grep as a filter: @matched  = grep /.../, <DATA>;


      Wow! Exactly on the spot! Thankyou! (Getting an answer in 17 minutes. I'm amazed!)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://125027]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2020-11-25 11:50 GMT
Find Nodes?
    Voting Booth?

    No recent polls found