我正在尝试使用正则表达式来匹配平衡的大括号,这些大括号会考虑并跳过转义大括号。
以下正则表达式不起作用。该脚本打印{ def \}
而不是预期的输出:{ def \} hij \\\} klm }
。我究竟做错了什么?我该如何改进呢?
my $str = 'abc { def \} hij \\\} klm } nop';
if ( $str =~ m/
(
\{
(?: \\\\
| \\[\{\}]
| [^\{\}]+
| (?-1)
)*
\}
)
/x
) { print $1, "\n" }
答案 0 :(得分:3)
这里有两个问题 - $str
中字符串的值和正则表达式
即使在单引号字符串中,当两个一起出现或者它们作为字符串中的最后一个字符出现时,必须转义反斜杠。一对反斜杠减少为一,因此子串\\\}
将在最终字符串中生成\\}
。要生成三个反斜杠后跟一个右括号,代码中需要六个反斜杠 - \\\\\\}
(尽管有五个反斜杠)
您的正则表达式模式不正确,因为字符类[^{}]
也会匹配单个反斜杠,这将阻止它被识别为转义大括号序列的一部分。因此备用[^{}\\]+
与字符串中的def \
匹配,使}
与其反斜杠分离
该程序可以满足您的需求
use strict;
use warnings 'all';
my $str = 'abc { def \} hij \\\\\\} klm } nop';
print $str, "\n";
if ( $str =~ m/
(
\{
(?:
[^{}\\]+ |
\\. |
(?-1)
)*
\}
)
/xs ) {
print $1, "\n";
}
abc { def \} hij \\\} klm } nop
{ def \} hij \\\} klm }
答案 1 :(得分:2)
您可以使用支持任何转义符号的以下正则表达式:
(?<=^|\\.|[^\\])({(?>\\.|[^{}]|(?1))*})
带有评论的VERBOSE版本:
(?<=^|\\.|[^\\]) # Before `{` there is either start of string, escaped entity or not a \
(
{ # Opening {
(?> # Start of atomic group
\\. # Any escaped symbol
|
[^{}] # any symbol but `{` and `}`
|
(?1) # Recurse the first subpattern
)* # repeat the atomic group 0 or more times
} # closing brace
)
请参阅regex demo
<强>更新强>
由于上述正则表达式可能会将转义的左括号与第一个字符匹配,因此您可以使用
[^\\{}]*(?:\\.[\\{}]*)*(?<!\\)({(?>\\.|[^{}]|(?1))*})
请参阅regex demo
它将匹配所有转义和不必要的子字符串,并捕获到第1组仅有效的子字符串。