You were surprised how your pattern matched, but noone explained it? Here's how your pattern is matching:
my @matches = $str =~ /{(?:{.*}|[^{])*}|w+/sg;
^ ^ ^ ^ ^ ^
| | | | | |
{ ---------------------+ | | | | |
a --------------------------)-)-)--+ |
b --------------------------)-)-)--+ |
c --------------------------)-)-)--+ |
} --------------------------)-)-)--+ |
--------------------------)-)-)--+ |
{ --------------------------+ | | |
{ ----------------------------+ | |
x ----------------------------+ | |
y ----------------------------+ | |
z ----------------------------+ | |
} ------------------------------+ |
} ----------------------------------------+
As you can see, the problem is that /{.*}
/ matches too much. What should be in there is a something that matches
(?: s* (?: { ... } | w+ ) )*
where the ...
is
(?: s* (?: { ... } | w+ ) )*
So you need some recursion. Named groups are an easy way of doing this.
say $1
while /
G s*+ ( (?&WORD) | (?&BRACKETED) )
(?(DEFINE)
(?<WORD> s* w+ )
(?<BRACKETED> s* { (?&TEXT)? s* } )
(?<TEXT> (?: (?&WORD) | (?&BRACKETED) )+ )
)
/xg;
But instead of reinventing the wheel, why not use Text::Balanced.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…