slok has asked for the wisdom of the Perl Monks concerning the following question:
given following
===
$default_str = "good food";
$string1 = $default_string;
$string2 = $default_string;
$string3 = $default_string;
$string1 =~ s/o*/e/;
print $string1;
$string2 =~ s/o+/e/;
$string3 = ~ s/o/e/g;
print $string1;
print $string2;
print $string3;
====
what I don't understand is why does pattern substitution for
$string1 and $string2 does not gave me the end results of
"geed feed" ?
Doesn't 1 and 2 look for "o"..
and for 1, it has a "*", which means "match 0 or more", right?
and for 2, it has a "+", which means match 1 or more times,
right?
thanks in advanced
Re: Pattern Substitution..
by arturo (Vicar) on May 30, 2001 at 17:39 UTC
|
Remember that pattern matches, by default, are *greedy*, so they match the longest string that conforms to the pattern. And unless you specify 'g' on the end, they only match the first substring that matches the pattern you specify.
So s/o*/e/ matches the first instance of "0 or more 'o's", and guess where that is? Right at the beginning of the string. When it says "match 0 or more", it means it =) So the result is "egood food".
With your second example, it only matches the first substring that's one or more 'o's, (the 'oo' in "good"), and replaces that with a single 'e' => 'ged food'.
HTH
perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>);
+$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth
+er_name\n"'
| [reply] [d/l] [select] |
Re: Pattern Substitution..
by davorg (Chancellor) on May 30, 2001 at 17:50 UTC
|
There are a number of things going wrong here, not least
of which is the fact that you are initialising $string1,
$string2 and $string3 to an empty string - not what you
think.
use strict would have caught this error.
But assuming that you do initialise all of your strings
to "good food", the three results you get are "egood food",
"ged food" and "geed feed" - which might also confuse you
a bit. Let's look at the three regexes in a bit more
detail.
s/o*/e/ says "look for zero or more
os and convert them to one e". The first
place you find zero or more os is at the start
of the string, so that is changed to an e.
s/o+/e/ says "look for one or more
os and convert them to one e". That finds
the oo in "good" and converts them to an
e.
s/o/e/g says "find one o and
convert it to an e, then repeat that process for
every o in the string".
--
<http://www.dave.org.uk>
"Perl makes the fun jobs fun
and the boring jobs bearable" - me
| [reply] |
Re: Pattern Substitution..
by Masem (Monsignor) on May 30, 2001 at 17:42 UTC
|
You have the meanings right, but remember that whatever is matched on the left side of the s/// operator is completely replaced by the right hand side. Since perl's re engine is greedy, it will match as many o's in a row in the o+ case, and replace them all with a single e, or simply see no o's at the start of the string in the o* case, and put an e in front. You might try to have perl ignore greedy behavior with s/o*?/e/ and s/o+?/e/ and see what interesting results you get.
Note that if all you are trying to do is replace one character with another, it's much easier to use tr than s.
For example:
$new_string = "good food";
$new_string =~ tr/od/ek/;
(update not like this as japhy points out...
$new_string = ( "good food" =~ tr/[od]/[ek]/; );
)
will give you "geek feek", with 'o' converted to 'e', and 'd' converted to 'k'.
Dr. Michael K. Neylon - mneylon-pm@masemware.com
||
"You've left the lens cap of your mind on again, Pinky" - The Brain
| [reply] [d/l] [select] |
|
No, it won't. tr/// in scalar context returns the number of characters translated; and the brackets are unnecessary. Not to mention, you're trying to modify a constant string.
<code>
($new_string = "good food") =~ tr/od/ek/;
japhy --
Perl and Regex Hacker
| [reply] |
Re: Pattern Substitution..
by suaveant (Parson) on May 30, 2001 at 17:41 UTC
|
ummm...
$default_str = "good food";
$string1 = $default_string;
you need to use the same variable name ;) perl -w will help catch errors like that.
Update arturo of course, is right too, dunno if your problem was the misspelling or if that just happened when you put the code on perlmonks
- Ant | [reply] |
Re: Pattern Substitution..
by Big Willy (Scribe) on May 30, 2001 at 22:30 UTC
|
The * and the + swallow up all of the o's and replace them with a single e. This is called greediness, meaning that a pattern will match as much of a string as it can, maximizing the length of the pattern matched.
If you want ungreedy operators that work in the opposite way, use *? and +?. In your simple situation, a e+? is as good as a plain old e, so it's not really necessary. The added ? becomes more useful with character sets like [aeiou] for example. You might also want to see the perl man page on regular expressions (perlre) for more info. | [reply] [d/l] [select] |
Re: Pattern Substitution..
by JP Sama (Hermit) on May 30, 2001 at 21:14 UTC
|
I think you should do something like that:
$string = qq{
what I don't understand is why does pattern substitution
$string1 and $string2 does not gave me the end results
of "geed feed" ?
Doesn't 1 and 2 look for "o".. and for 1, it has a "*",
which means "match 0 or more", right?
and for 2, it has a "+", which means match 1 or more
times, right? thanks in advanced
};
$string =~ s/o/e/g;
print $string;
That should work... the last "g" is for GLOBAL.
Regards!
#!/jpsama/bin/perl -w
$tks = `mount`;
$jpsama = $! if $!;
print $jpsama;
| [reply] [d/l] |
|
|