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;
| [reply] [Watch: Dir/Any] [d/l] |
|
while(<>) {
print "yes\n" if /(^y$|^yes$)/i;
}
| [reply] [Watch: Dir/Any] [d/l] |
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
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.
| [reply] [Watch: Dir/Any] |
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
| [reply] [Watch: Dir/Any] [d/l] |
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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;
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
|
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
| [reply] [Watch: Dir/Any] [d/l] |
|
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.
| [reply] [Watch: Dir/Any] |
|
|
|
Re: conditional regex
by suhailck (Friar) on Aug 22, 2010 at 08:34 UTC
|
| [reply] [Watch: Dir/Any] |
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
| [reply] [Watch: Dir/Any] [d/l] |
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;
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Simplicity is all in the eye of the Maintenance Programmer....
----
I Go Back to Sleep, Now.
OGB
| [reply] [Watch: Dir/Any] |