gpt4 book ai didi

c# - 如何进行正则表达式平衡匹配,当括号可能是 'escaped'

转载 作者:行者123 更新时间:2023-11-30 16:12:35 25 4
gpt4 key购买 nike

假设我有一个具有以下字符串的玩具语言:

fun( fun3\(\) ) + fun4()

在这里,“fun”接收“fun3()”作为其参数。 fun4() 留待以后评估。

现在假设我有一个不同的字符串:

fun( fun3()\\) )

这里,'fun' 应该接收 'fun3()\' 并且我们有 ) 剩余。

通过执行 '\' 转义 '\' 意味着我们从字面上理解它 - 因此,/that pair/of '\'s 不再转义括号。第三个\将再次转义括号等。

现在,假设我想使用 C#) 的更强大的 Regex 库来匹配这个字符串,使用它匹配方括号的方式,特别是;我知道通常我会使用适当的解析方法而不是(扩展的)正则表达式。这不是关于我应该使用什么工具,而是关于这个工具可以做什么。

我将使用以下三个字符串作为我的测试。

fun(abc) fun3()

这意味着 fun() 接收“abc”作为其参数。 fun3() 是剩余的。

fun(\\\)\)) fun3()

这意味着 fun() 接收 '\))' 作为它的参数。 fun3() 是剩余的。

fun(fun2(\)\\\() ) fun3()

这意味着 fun() 接收 'fun2()\()' 作为其参数。 fun3() 是剩余的。

正如 Alan Moore 在 this StackOverflow question 中推测的那样,我首先要使用的是 LookBehind。下面的正则表达式处理第一种情况,但显然不是第二种情况。采取它看到的第一个 ')' 太快了。

Regex catchRegex = new Regex(@"^fun\((.*?(?<!\\)(?:\\\\)*)(?<ClosingChar>[\)])(.*$)");
string testcase0 = @"fun(abc) fun3()";
string testcase1 = @"fun(\\\)\)) fun3()";
string testcase2 = @"fun(fun2(\)\\\() ) fun3()";
Console.WriteLine(catchRegex.Match(testcase0).Groups[1]); // 'abc'
Console.WriteLine(catchRegex.Match(testcase0).Groups[2]); // ' fun3()'
Console.WriteLine(catchRegex.Match(testcase0).Groups[3]); // ')'

Console.WriteLine(catchRegex.Match(testcase1).Groups[1]); // '\\\)\)'
Console.WriteLine(catchRegex.Match(testcase1).Groups[2]); // ' fun3()'
Console.WriteLine(catchRegex.Match(testcase1).Groups[3]); // ')'

Console.WriteLine(catchRegex.Match(testcase2).Groups[1]); // 'fun2(\)\\\(' <--!
Console.WriteLine(catchRegex.Match(testcase2).Groups[2]); // ' ) fun3()' <--!
Console.WriteLine(catchRegex.Match(testcase2).Groups[3]); // ')'

现在我们开始做 .NET 可以做的事情。支架匹配。它通过了第一个测试......但是因为我没有告诉它不要关心逃脱的事情,所以它没有通过其他测试。这才公平。

Regex bracketRegex = new Regex(@"^fun\(([^\)]*|(?<BR>)\(|(?<-BR>)\))(?<ClosingChar>[\)])(.*$)");
Console.WriteLine(bracketRegex.Match(testcase0).Groups[1]); // 'abc'
Console.WriteLine(bracketRegex.Match(testcase0).Groups[2]); // ' fun3()'
Console.WriteLine(bracketRegex.Match(testcase0).Groups[3]); // ''

Console.WriteLine(bracketRegex.Match(testcase1).Groups[1]); // '\\\'
Console.WriteLine(bracketRegex.Match(testcase1).Groups[2]); // '\)) fun3()'
Console.WriteLine(bracketRegex.Match(testcase1).Groups[3]); // ''

Console.WriteLine(bracketRegex.Match(testcase2).Groups[1]); // 'fun2(\' <--!
Console.WriteLine(bracketRegex.Match(testcase2).Groups[2]); // '\\\() ) fun3()' <--!
Console.WriteLine(bracketRegex.Match(testcase2).Groups[3]); // ''

但问题是下一步。结合版本 1 和版本 2 实际上并没有给我任何东西或任何地方。那么问题来了,StackOverflow,有没有办法做到这一点?

Regex bracketAwareRegex = new Regex(@"^fun\(([^\)]*|(?<BR>)(?<!\\)(?:\\\\)*\(|(?<-BR>)(?<!\\)(?:\\\\)*\))(?<ClosingChar>[\)])(.*$)");
Console.WriteLine(bracketAwareRegex.Match(testcase0).Groups[1]); // 'abc'
Console.WriteLine(bracketAwareRegex.Match(testcase0).Groups[2]); // ' fun3()'
Console.WriteLine(bracketAwareRegex.Match(testcase0).Groups[3]); // ''

Console.WriteLine(bracketAwareRegex.Match(testcase1).Groups[1]); // '\\\'
Console.WriteLine(bracketAwareRegex.Match(testcase1).Groups[2]); // '\)) fun3()'
Console.WriteLine(bracketAwareRegex.Match(testcase1).Groups[3]); // ''

Console.WriteLine(bracketAwareRegex.Match(testcase2).Groups[1]); // 'fun2(\' <--!
Console.WriteLine(bracketAwareRegex.Match(testcase2).Groups[2]); // '\\\() ) fun3()' <--!
Console.WriteLine(bracketAwareRegex.Match(testcase2).Groups[3]); // ''

因为那行不通。

最佳答案

我建议这个正则表达式:

@"^fun\(((?:[^()\\]|\\.|(?<o>\()|(?<-o>\)))+(?(o)(?!)))\)(.*$)"

ideone demo

我删除了 ClosingChar 捕获。

结果:

string testcase0 = @"fun(abc) fun3()";
Console.WriteLine(catchRegex.Match(testcase0).Groups[1]); // 'abc'
Console.WriteLine(catchRegex.Match(testcase0).Groups[2]); // ' fun3()'

string testcase1 = @"fun(\\\)\)) fun3()";
Console.WriteLine(catchRegex.Match(testcase1).Groups[1]); // '\\\)\)'
Console.WriteLine(catchRegex.Match(testcase1).Groups[2]); // ' fun3()'

string testcase2 = @"fun(fun2(\)\\\() ) fun3()";
Console.WriteLine(catchRegex.Match(testcase2).Groups[1]); // 'fun2(\)\\\()'
Console.WriteLine(catchRegex.Match(testcase2).Groups[2]); // ' fun3()'

我有另一种处理转义字符的方法,它使用的有点像:

(?:[^()\\]|\\.)

当与平衡组结合时,以上述结束。

^fun\(            Match 'fun(' literally at the beginning
(
(?:
[^()\\] Match anything not '(', ')' or '\'
|
\\. Match any escaped char
|
(?<o>\() Match a '(' and name it 'o'
|
(?<-o>\)) Match a ')' and remove the named 'o' capture
)+
(?(o)(?!)) Make regex fail if 'o' doesn't exist
)
\)(.*$) Match anything leftover

关于c# - 如何进行正则表达式平衡匹配,当括号可能是 'escaped',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22745729/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com