您对您的模式如何匹配感到惊讶,但没有人解释它?以下是您的模式匹配方式:
my @matches = $str =~ /\{(?:\{.*\}|[^{])*\}|\w+/sg;
^ ^ ^ ^ ^ ^
| | | | | |
{ ---------------------+ | | | | |
a --------------------------)-)-)--+ |
b --------------------------)-)-)--+ |
c --------------------------)-)-)--+ |
} --------------------------)-)-)--+ |
--------------------------)-)-)--+ |
{ --------------------------+ | | |
{ ----------------------------+ | |
x ----------------------------+ | |
y ----------------------------+ | |
z ----------------------------+ | |
} ------------------------------+ |
} ----------------------------------------+
如您所见,问题在于\{.*\}
// 匹配太多。里面应该有一个匹配的东西
(?: \s* (?: \{ ... \} | \w+ ) )*
...
在哪里
(?: \s* (?: \{ ... \} | \w+ ) )*
所以你需要一些递归。命名组是一种简单的方法。
say $1
while /
\G \s*+ ( (?&WORD) | (?&BRACKETED) )
(?(DEFINE)
(?<WORD> \s* \w+ )
(?<BRACKETED> \s* \{ (?&TEXT)? \s* \} )
(?<TEXT> (?: (?&WORD) | (?&BRACKETED) )+ )
)
/xg;
但是,与其重新发明轮子,不如使用Text::Balanced。