Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

conditional regex

by Anonymous Monk
on Aug 22, 2010 at 07:04 UTC ( [id://856559]=perlquestion: print w/replies, xml ) Need Help??

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

I always wonder about how to do the following, match y or yes in case-insensitive manner. /y(es)?/i which matches ys or ye also, but how to match s only if e is there, and match e only if s is there ?
while(<>) { print "yes\n" if /y(es)?/i; }
Hope it is clear.. Any help is appreciated.

Replies are listed 'Best First'.
Re: conditional regex
by ikegami (Patriarch) on Aug 22, 2010 at 07:09 UTC
    What you have will match anything that contains "y" or "Y" (e.g. "xyz") because you didn't specify where the characters must occur.
    print "yes\n" if /^y(?:es)?$/i;

      If the expected input is y or yes in a line then following code can be used simply.

      while(<>) { print "yes\n" if /(^y$|^yes$)/i; }
        So could
        while(<>) { print "yes\n" if /^y$/i || /^yes$/i; }
        while(<>) { print "yes\n" if /^y$/i; print "yes\n" if /^yes$/i; }

        By the way, useless capturing greatly slows down pattern matching.

Re: conditional regex
by merlyn (Sage) on Aug 22, 2010 at 16:22 UTC
    /y(es)?/i which matches ys or ye also,
    No it doesn't. The "es" is optional, so it matches "y" or "yes". Never "ye" or "ys".

    -- Randal L. Schwartz, Perl hacker

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

Re: conditional regex
by Marshall (Canon) on Aug 22, 2010 at 08:23 UTC
    You have to specify that you are looking at the beginning of the line for the "yEs" or that spaces in front do not matter.

    This question often comes up in the context of "how do I write a simple command line loop"?

    There are very few times in 'C' or in Perl where the comma operator makes sense to use, but this is one of them! This is an interactive thing that you can play with...go for it! Fiddle with the regex and see what it does!

    Some Monks prefer more complex formulations of this command line loop algorithm. I think the important part here is for you to understand how to "drive the regex part".

    #!/usr/bin/perl -w use strict; while ( (print "Enter some text: "), (my $line=<STDIN>) !~ /^\s*q(uit)?\s*$/i ) { next if $line =~ /^\s*$/; #blank line just re-prompts chomp ($line); # a real app would probably do this print "$line\n"; # although here I just add it back } print "program exited\n"; __END__ C:\TEMP>stdcmdline.pl Enter some text: 25436 25436 Enter some text: QuIT progam exited C:\TEMP>stdcmdline.pl Enter some text: quI quI Enter some text: Q progam exited C:\TEMP>stdcmdline.pl Enter some text: asdf asdf Enter some text: qu qu Enter some text: QuIT program exited C:\TEMP>stdcmdline.pl Enter some text: quited quited Enter some text: 3245 3245 Enter some text: Q program exited C:\TEMP>stdcmdline.pl Enter some text: q program exited C:\TEMP>stdcmdline.pl Enter some text: quit program exited
Re: conditional regex
by BrowserUk (Patriarch) on Aug 22, 2010 at 09:37 UTC

    Update: All '*' corrected to be '?' per follow ups.

    but how to match s only if e is there, and match e only if s is there ?

    I don't think anyone actually answered your question.

    For proper abbreviations of 'yes', you can use m[^Y(?:E(?:S)?)?$]i.

    That's a bit unweildy, but the repetitious nature means it is quite easy to generate a regex for any given word:

    sub genAbbrevRegex{ my( $first, @rest ) = split '', shift; my $re = ''; $re = "(?:$_$re)?" for reverse @rest; return qr[^$first$re$]i; } print genAbbrevRegex( 'fred' );; (?i-xsm:^f(?:r(?:e(?:d)?)?)?$) $r = genAbbrevRegex( 'Yes' );; [0] Perl> print "$_: ", m[$r]? 'ok' : 'not ok' for qw[ YES YE Y yes ye + y YS ES S ys es s yees yess ];; YES: ok YE: ok Y: ok yes: ok ye: ok y: ok YS: not ok ES: not ok S: not ok ys: not ok es: not ok s: not ok yees: not ok yess: not ok

    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.
      Your pattern also matches 'YEESS', 'yeeeeeeeeeeeeeeeeeees', and 'YeEeEeEeSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS'.

      Probably not what you want.

      There's a much simpler solution. Reverse the subject and the pattern:

      for my $str (qw[YES YE Y yes ye y YS ES S ys es s YEESS YYYEEs]) { say "$str: ", "yes" =~ /^\Q$str/i ? "ok" : "not ok"; } __END__ YES: ok YE: ok Y: ok yes: ok ye: ok y: ok YS: not ok ES: not ok S: not ok ys: not ok es: not ok s: not ok YEESS: not ok YYYEEs: not ok
      Or, instead of the pattern match:
      say "ok" unless index "yes", lc $str;

        Indeed that is much simpler. I wish I'd thought of it :)

      Even though it might be considered a really, really emphatic variation of 'Yes', the solution of Re: conditional regex will accept something like 'Yeeessseeseeesssssess'. Wouldn't an approach like the following be better:

      >perl -wMstrict -le "sub genAbbrevRegex{ my ($first, @rest) = split '', shift; my $re = ''; $re = qq{(?: $_ $re)?} for reverse @rest; return qr{ $first $re }xmsi; } print genAbbrevRegex( 'fred' );; my $r = genAbbrevRegex( 'Yes' );; print $r; print qq{'$_': }, m{ \A $r \z }xms ? 'ok' : 'not ok' for qw[ YES YE Y yes ye y ys es s e Yeeessseeseeesssssess];; " (?msix: f (?: r (?: e (?: d )?)?)? ) (?msix: Y (?: e (?: s )?)? ) 'YES': ok 'YE': ok 'Y': ok 'yes': ok 'ye': ok 'y': ok 'ys': not ok 'es': not ok 's': not ok 'e': not ok 'Yeeessseeseeesssssess': not ok

        Of course, it should have been 0 or 1 not 0 or many.

        I don't see any advantage in using /msx, nor \A & \z for this?

        (Nor qq{} when simple quotes do, but that a personal beef. PBP has a lot to answer for :)


        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: conditional regex
by suhailck (Friar) on Aug 22, 2010 at 08:34 UTC
    ui
    by Marshall (Canon) on Aug 22, 2010 at 08:51 UTC
      I looked at your link. This is more along the lines of if-then logic and I don't think that is what is being requested here.

      My code above is more along the lines of if X OR Y happens, then we do Z. To be specific: (a)ignore any white space before or after the stuff that was typed in. (b) If "the stuff" (exclusive of leading or trailing white space) typed into the line is: q,Q,QUiT,quit or something similar in a upper or lower case insensitive manner then, the program stops - that's the "Z" action.

      Update: the code is very specific about what it "needs":
      Some more test cases shown below

      C:\TEMP>stdcmdline.pl Enter some text: quitme quitme Enter some text: quit me quit me Enter some text: Quit me Quit me Enter some text: QuIt program exited
Re: conditional regex
by BrimBorium (Friar) on Aug 22, 2010 at 17:24 UTC

    for a simple question I would prefer a simple solution (maybe not so perfect but easy to understand also to non-regexperts). This does exactly "match y or yes in case-insensitive manner":

    while(<>) { print "yes\n" if /(y|yes)/i; }

    update: above will match everything with a 'y' inside as ikegami observed. Below code does what I meant (this time tested before posting)

    foreach (qw( YES YE Y yes ye y ys es s e Yeeessseeseeesssssess)){ print "$_ = yes\n" if /^(y|yes)$/i; }
      Try typing "fluffy"

        I guess you don't mean I should use a ball of cotton ...

        what do you mean with typing "fluffy" ?

Re: conditional regex
by TomDLux (Vicar) on Aug 23, 2010 at 02:36 UTC

    Why make things so complicated? You want to match /[yY](?:[eE][sS])?/ ... but 'eq' is so much simpler ...

    my $word = lc $_; print "yes\n" if $word eq 'y' or $word eq 'yes';
    I think I need to make Occam's Razore my new .sig ... no one else seems to be defending the concept.

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

      chomp needed.

      I wouldn't necessarily call

      chomp( my $word = lc $_ ); if $word eq 'y' or $word eq 'yes';
      simpler than
      if /^y(?:es)?$/i;

      Maybe it's more complex to write, but surely it's simpler to read.

      Simplicity is all in the eye of the Maintenance Programmer....

      ----
      I Go Back to Sleep, Now.

      OGB

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://856559]
Approved by ikegami
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2024-03-28 21:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found