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

I am wondering if there is an and or operator. I am trying to run a match with multiple patterns and return the match whether it is multiple or single. this seems to have worked for 2 but any more gets buggy and only prints the first occurrence of a match, I am thinking an and/or statement in the match would allow the info to be carried forward something like &| maybe?: .... if ($element =~m/(WEED)|(DIAL)|(PIES)|(KILLD)/gs) { $match = $1||$2||$3||$4; print " $fastaheader : $match \n"; } }

Replies are listed 'Best First'.
Re: and or statement
by AnomalousMonk (Archbishop) on Nov 08, 2011 at 00:18 UTC

    I don't understand the question. Why not just capture what was matched, as in (note that the /g regex modifier is not used; it almost certainly does not do what you expect):

    >perl -wMstrict -le "my $element = 'hi WEED ho'; if ($element =~ m{ (WEED|DIAL|PIES|KILLD) }xms) { my $match = $1; print qq{match: '$match'}; } " match: 'WEED'
      sorry what I want to do is return matches of each word in a short statement rather than re iterating through multiple if statements; so that the first match stores the occurrence of each match ie $1 contains weed if matched $2 has dial etc so if the queried scalar contains weed AND dial both are printed. (The code also calls the scalar of the matched file with is the $fasta header part of a foreach loop) or if only one is present one is printed. so match weed and or dial and print the matched quantity. I apologize for being vague I am fairly new at this.

        I'm still a bit vague about your requirements, but something along these lines might serve (note /g regex modifier is required in  m{ ... }xmsg below):

        >perl -wMstrict -le "my @motifs = qw(WEED KILLD DIAL PIES); my $motif = join '|', @motifs; $motif = qr{ $motif }xms; ;; my $element = 'both WEED PIES and DIAL PIES are present'; ;; my %elements = map { $_ => 1 } $element =~ m{ $motif }xmsg ; ;; printf qq{$_ is %spresent \n}, $elements{$_} ? '' : 'NOT ' for @motifs; ;; my @present = keys %elements; print qq{present: @present}; " WEED is present KILLD is NOT present DIAL is present PIES is present present: WEED DIAL PIES

        Update: The  map statement could easily be changed to count the number of occurrences of each 'motif', if that's the correct terminology.

        An AND+OR operator makes no sense. Reductio ad absurdum, let's say such an operator exists and is denoted by -&|-

        Consider:
        if ( (1 == 1) -&|- (1 == 2) ) { # duh! fixed '=' to '==' 8 Nov say "yep! one is equal to one and/or one is equal to two"; }

        For an explanation of alternation in a regex, you'll do well to read perlrequick and perlretut... but pay special attention to the explanation (paraphrased) that the first-matched alternative wins.

        If you want a count of instances of any given sequence which is (or is not) repeated in the data, you'll want to read about hashes ... for instance, in Not Exactly a Hash Tutorial which is found, along with others, in Tutorials.

        And, since you're "fairly new at this," here are a few hints:

        • Until you know exactly why to omit them, use strict and warnings. They'll save you much heartburn over your typos ... and outright syntax errors like...
        • $match = $1||$2||$3||$4; from your OP. $match won't contain what you appear to expect without double-quotes.
        • And speaking of expectations, the Monks expect those who post questions to read the formatting advice re <p>...</p> and <c>...</c> found adjacent to the text-input box where the poster types the question. The code tags advice applies BOTH to code AND to data. See also Markup in the Monastery.

        And, lest this seem a heavy burden, you've already taken the hardest step: starting. Welcome to the Monastery, where you'll find many willing to help with pointers and explanations.

Re: and or statement
by ikegami (Patriarch) on Nov 08, 2011 at 00:08 UTC

    Your question is very unclear. It's hard to tell what you want to obtain. Maybe

    my @matches = ( $element =~ /(WEED)/, $element =~ /(DIAL)/, $element =~ /(PIES)/, $element =~ /(KILLD)/, ); if (@matches) { ... }

    The above can be shortened by using map as a topicaliser.

    if (my @matches = map { /(WEED)/, /(DIAL)/, /(PIES)/, /(KILLD)/ } $ele +ment) { ... }

    Update: If you don't mind one of the strings appearing twice if it appears twice in $element, you can use

    if (my @matches = $element =~ /(WEED|DIAL|PIES|KILLD)/g) { ... }
      1. Agree heartily with previous respondents, ikegami and AnomalousMonk: Your intent is unclear.
      2. Your sample data (which sometimes makes our crystal balls more useful) is missing.
      3. ...and, further re ikegami's solution:

      If your $element = "WEED BECAUSE PIPES KILLD THE PIES WITHOUT DIAL. PIPES ARE NOT GOOD FOR PIES.";

      his multi-regex solution will tolerate use of /g, and -- with the addition of this code,

      if (@matches) { for ( @matches ) { say $_; } }

      -- will produce this output:

      WEED DIAL PIES PIES KILLD
        I like it yes that will work nicely. Sorry it was just a module of a larger piece to find motifs in a fasta formatted data set containing multiple fasta sequences from a file which I input as asked. I parsed the fasta sequence w/ a foreach loop and after each is parsed it runs this (match) part of the loop on the sequence data to discover whether the sequence contains the motifs or patterns. I only need one match per pattern, but have multiple patterns and require ID of each match case (ie only return pies once despite the number of occurrences; if pies and weed is found multiple times return both, but only once to indicate presence.
Re: and or statement
by eyepopslikeamosquito (Archbishop) on Nov 08, 2011 at 01:40 UTC
Re: and or statement
by JavaFan (Canon) on Nov 08, 2011 at 01:54 UTC
    Untested:
    $element =~ /$_/p and print "$fastaheader: ${^MATCH}\n" for qw[WEED DI +AL PIES KILLD];
Re: and or statement
by locked_user sundialsvc4 (Abbot) on Nov 08, 2011 at 13:22 UTC

    One strategy that often works well is to write a regex that will match any of the words desired (hint:   don’t forget the \b escape to match end-of-word), then push each word as-found onto a queue.

    After finding a word, examine the top n entries in the list to see if the desired sequence has been found.   If so, shift off all of the words.

    If the total size of the stack exceeds the number of words sought, shift off and discard words to make room, taking care always to be manipulating the front of the stack (oldest entries).