It's even easier to use split since you have a repeating structure. Chop off the first and last characters, then split it on = and spaces, and you should end up with an list of all the characters left. I assume that putting them in a hash would be appropriate, so you can just do exactly that with the return value.
my %values = split /\=|\s/ => substr($string, 1, -1);
-stvn | [reply] [d/l] [select] |
If you can guarantee the format before hand, pre-generated or whatever....
$x="ab[x=1 y=2 z=5] cd [z=4] ef";
@y = ($x=~/\[(.*?)\]/g) ;
print join ", ", ( split /[\[\]= ]+/, ( join " ", @y ) ) ;
Play that funky music white boy..
| [reply] [d/l] |
Capture parens will only return one value per application of the regex. Your try has three sets, so it will return three values, no matter how many times that *? repeats.
To do what you want, you need the //g flag:
$x="[x=1 y=3 z=5]";
print join ":", $x=~/(\w+)=(\d+)/g;
That just skips over the [, ], and spaces around your = pairs.
The above will treat foo-bar=5 as bar=5, ignoring the "foo-" since it has a non-\w char.
To know that your regex is parsing the complete string successfully, do it like this:
print join ":", $x=~/\G # start where prev match left off
(?:\A\[)? # if start of string, expect [
(\w+)=(\d+) # our data
(?:\s(?!\z) # between pairs, expect \s
|\]\z) # or if end of string, expect ]
/gcx;
# if whole string was parsed, pos will be defined and equal to length
print "error" unless pos($x) && pos($x) == length($x);
This is a very useful idiom (to me anyway). It looks fairly complicated at first, but once you go through and understand it, you can see that most of it stays the same for different applications. You just replace the first \[, the data line, the \s, and the last \[ as appropriate for what you are parsing. | [reply] [d/l] [select] |
An alternative solution, I would use the regex capture similar/same to what ysth did in the first half of his reply, but combine with the useful @ary = $str =~ /(pattern)/g idiom...
use strict;
use warnings;
use Data::Dumper;
my $str = "[x=1 y=3 z=5] {a=1 b=2 c=3} [d=4 e=5 f=6]";
my @ary = map { /(\w+)=(\d+)/g } # capture foo=bar
$str =~ /\[([^\]]+)\]/g; # but only between [ and ]
print Dumper(\@ary);
| [reply] [d/l] [select] |
Since you don't define how your definitions look like - all
you do is give a simple example, I'll just assume that there
are word characters on both the left and right hand side of
the equal sign, and there are no other word characters in the
string.
In that case,
@results = $str =~ /\w+/g;
will do.
Abigail | [reply] [d/l] |