On 17/03/2011 20:27, Chap Harrison wrote:
On Mar 17, 2011, at 1:49 PM, C.DeRykus wrote:
On Mar 16, 9:58 am, c...@pobox.com (Chap Harrison) wrote:
[snip]
my $line = 'min=2 max = 12 weighted total= 20';
$line = 'min=2 max, = 12 weighted total= 20';
say $line;
my %param;
if ( $line and
($line !~
s/
\G # Begin where prev. left off
(?: # Either a parameter...
(?: # Keyword clause:
(\w+) # KEYWORD (captured $1)
(?: # Value clause:
\s* #
= # equal sign
\s* #
(\w+) # VALUE (captured $2)
)? # Value clause is optional
)
\s* # eat up any trailing ws
) ###<-- moved
| # ... or ...
$ # End of line.
/ # use captured to set %param
$param{uc $1} = ( $2 ? $2 : 1 ) if defined $1;
/xeg
) ) {
say "Syntax error: '$line'";
while (my ($x, $y) = each %param) {say "$x='$y'";}
exit;}
while (my ($x, $y) = each %param) {say "$x='$y'";}
I believe the problem is the "? # Value clause is optional"
since, in the case of your badline with a ",", the regex will
consume 'max' and then ignore the , since ? means 0 or 1
instance. Therefore the regex will still succeed and $2 will
be undefined. So the VALUE gets set to 1.
I agree - encountering the ',' causes the regex to think it's
encountered a keyword without a value. But why doesn't the *next*
iteration of the global substitution (which would begin at the ',')
fail, causing the if-statement to succeed and print "Syntax error"?
Perhaps I don't fully understand how the /g option works.... I
thought it would continue to "iterate" until either it reached the
end of the string (in which case the s/// would be considered to have
succeeded) or it could not match anything further (in which case it
would be considered to have failed).
Hi Chap
A s///g is 'successful' if it performs at least one substitution, in
which case it will return the number of substitutions made. In your
code, it will find as many key=value substrings as possible and replace
them with just the value string.
The \G pattern is documented only in the case of m//g, which makes sense
as it is defined in terms of a character position (pos) within the
string where the last match ended. If a substitution is being made then
it will also affect character positions, and so is similar to adding to
or deleting from an array while iterating over it.
It is bad form to use the /e modifier to generate side-effects (just as
it is wrong to do so with the map operator).
I believe a while loop is the proper way to go, but if you want to
experiment with m//g I suggest something like this
my %matches = $line =~ /\G\s*(\w+)(?:\s*=\s*(\w+))?\s*/gc;
which will pass all the 'key' and 'key=value' pairs to %matches. An
invalid input will cause the match to terminate before the end of the
string, so
if (pos $line < length $line) {
# code to handle bad input
}
If a key has no corresponding value in the string it will appear in the
hash with a value of undef, which should be defaulted to 1 like this
foreach (values %matches) {
$_ = 1 if not defined;
}
I hope that helps a little.
Rob
--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/