灾难性的回溯;正则表达式,用于提取嵌套括号中的值

时间:2019-11-10 08:42:27

标签: c# regex .net-core

我想使用正则表达式从以下字符串中提取aaabb b={{b}}bb bbb{ccc} ccc

zyx={aaa}, yzx={bb b={{b}}bb bbb}, xyz={{ccc} ccc}

注意:aaa代表任意数量的字符的任意序列,因此没有确定的长度或图案。例如,{ccc} ccc可以是{cccccccccc}cc {cc} cccc cccc或任何其他组合),

我写了以下正则表达式:

(?<a>[^{}]*)\s*=\s*{((?<v>[^{}]+)*)},*

此表达式提取了aaa,但是由于嵌套了花括号,因此无法使用catastrophic backtracking failure来解析其余的输入。

关于如何更新正则表达式以正确处理嵌套括号的任何想法?

(以防万一,如果您需要特定于引擎的选项,我正在使用C#.NET Core 3.0。此外,我宁愿对代码不做任何魔术,而仅使用正则表达式模式。)


类似的问题

问题regular expression to match balanced parentheses与该问题类似,不同之处在于,这里的括号不一定是平衡的,而是遵循x={y}模式。


更新1

也可以输入以下内容:

yzx={bb b={{b}},bb bbb,}, 

请注意,{{b}}之后的bbb


更新2

我写了以下模式,它可以匹配第一个示例中除aaa以外的任何内容:

(?<A>[^{}]*)\s*=\s*{(?<V>(?<S>([^{}]?)\{(?:[^}{]+|(?&S))+\}))}(,|$)

1 个答案:

答案 0 :(得分:0)

Regex.Matches,非常好

"={(.*?)}(, |$)"可以工作。

string input = "zyx={aaa}, yzx={bb b={{b}}bb bbb}, yzx={bb b={{b}},bb bbb,}, xyz={{ccc} ccc}";

string pattern = "={(.*?)}(, |$)";

var matches = Regex.Matches(input, pattern)
        .Select(m => m.Groups[1].Value)
        .ToList();

foreach (var m in matches) Console.WriteLine(m);

输出

aaa
bb b={{b}}bb bbb
bb b={{b}},bb bbb,
{ccc} ccc

Regex.Split,非常好

我认为Regex.Split可能是更好的工具。

tring input = "zyx={aaa}, yzx={bb b={{b}}bb bbb}, yzx={bb b={{b}},bb bbb,}, ttt={nasty{t, }, }, xyz={{ccc} ccc}, zzz={{{{{{{huh?}";
var matches2 = Regex.Split(input, "(^|, )[a-zA-Z]+=", RegexOptions.ExplicitCapture); // Or "(?:^|, )[a-zA-Z]+=" without the flag


Console.WriteLine("-------------------------"); // Adding this to show the empty element (see note below)
foreach (var m in matches2) Console.WriteLine(m);
Console.WriteLine("-------------------------");
-------------------------

{aaa}
{bb b={{b}}bb bbb}
{bb b={{b}},bb bbb,}
{nasty{t, }, }
{{ccc} ccc}
{{{{{{{huh?}
-------------------------

注意:because中是空元素:

  

如果在输入字符串的开头或结尾找到匹配项,则在返回数组的开头或结尾包含一个空字符串。

案例3

string input = "AAA={aaa}, BBB={bbb, bb{{b}}, bbb{b}}, CCC={ccc}, DDD={ddd}, EEE={00-99} ";
var matches2 = Regex.Split(input, "(?:^|, )[a-zA-Z]+="); // Or drop '?:' and use RegexOptions.ExplicitCapture

foreach (var m in matches2) Console.WriteLine(m);

{aaa}
{bbb, bb{{b}}, bbb{b}}
{ccc}
{ddd}
{00-99}