gpt4 book ai didi

c# - 如何在 Regex 中指定匹配模式的优先级?

转载 作者:太空狗 更新时间:2023-10-29 20:18:28 25 4
gpt4 key购买 nike

我正在编写一个函数解析引擎,它使用正则表达式来分隔各个术语(定义为常量或变量,后跟(可选)运算符)。它工作得很好,除非我在其他分组术语中对术语进行分组。这是我正在使用的代码:

//This matches an opening delimiter
Regex openers = new Regex("[\\[\\{\\(]");

//This matches a closing delimiter
Regex closers = new Regex("[\\]\\}\\)]");

//This matches the name of a variable (\w+) or a constant numeric value (\d+(\.\d+)?)
Regex VariableOrConstant = new Regex("((\\d+(\\.\\d+)?)|\\w+)" + FunctionTerm.opRegex + "?");

//This matches the binary operators +, *, -, or /
Regex ops = new Regex("[\\*\\+\\-/]");

//This compound Regex finds a single variable or constant term (including a proceeding operator,
//if any) OR a group containing multiple terms (and their proceeding operators, if any)
//and a proceeding operator, if any.
//Matches that match this second pattern need to be added to the function as sub-functions,
//not as individual terms, to ensure the correct evalutation order with parentheses.
Regex splitter = new Regex(
openers +
"(" + VariableOrConstant + ")+" + closers + ops + "?" +
"|" +
"(" + VariableOrConstant + ")" + ops + "?");

当“splitter”匹配字符串“4/(2*X*[2+1])”时,匹配的值为“4/”、“2*”、“X*”、“2” +”和“1”,完全忽略所有定界括号和大括号。我相信这是因为“拆分器”正则表达式的后半部分(“|”之后的部分)正在匹配并覆盖模式的另一部分。这很糟糕——我希望分组表达式优先于单个术语。有谁知道我该怎么做?我研究过使用正面/负面前瞻和后视,但老实说我不确定如何使用它们,或者它们的用途,就此而言,我找不到任何相关的例子......提前致谢.

最佳答案

您没有向我们展示您是如何应用正则表达式的,所以这是我制作的演示:

private static void ParseIt(string subject)
{
Console.WriteLine("subject : {0}\n", subject);

Regex openers = new Regex(@"[[{(]");
Regex closers = new Regex(@"[]})]");
Regex ops = new Regex(@"[*+/-]");
Regex VariableOrConstant = new Regex(@"((\d+(\.\d+)?)|\w+)" + ops + "?");

Regex splitter = new Regex(
openers + @"(?<FIRST>" + VariableOrConstant + @")+" + closers + ops + @"?" +
@"|" +
@"(?<SECOND>" + VariableOrConstant + @")" + ops + @"?",
RegexOptions.ExplicitCapture
);

foreach (Match m in splitter.Matches(subject))
{
foreach (string s in splitter.GetGroupNames())
{
Console.WriteLine("group {0,-8}: {1}", s, m.Groups[s]);
}
Console.WriteLine();
}
}

输出:

subject : 4/(2*X*[2+1])

group 0 : 4/
group FIRST :
group SECOND : 4/

group 0 : 2*
group FIRST :
group SECOND : 2*

group 0 : X*
group FIRST :
group SECOND : X*

group 0 : [2+1]
group FIRST : 1
group SECOND :

如您所见,术语 [2+1] 与正则表达式的第一部分匹配,如您所愿。但是,它不能对 ( 做任何事情,因为紧随其后的下一个括号字符是另一个“开场白”([),它正在寻找一个“closer” .

可以使用 .NET 的“平衡匹配”功能来允许包含在其他组中的分组术语,但这不值得付出努力。正则表达式不是为解析而设计的——事实上,解析和正则表达式匹配是根本不同的操作。这是区别的一个很好的例子:正则表达式主动寻找匹配项,跳过它不能使用的任何东西(比如你的例子中的左括号),但是解析器必须检查每个字符(即使它只是为了决定忽略它)。

关于演示:我尝试进行最少的功能更改以使您的代码正常工作(这就是为什么我没有更正将 + 在捕获组之外),但我也进行了一些表面更改,这些更改代表了积极的建议。即:

  • 在 C# 中创建正则表达式时始终使用逐字字符串文字 (@"...")(我认为原因很明显)。
  • 如果您使用捕获组,请尽可能使用命名组,但不要在同一个正则表达式中使用命名组和编号组。命名组让您无需跟踪捕获的内容,而 ExplicitCapture 选项让您不必在任何地方用 (?:...) 弄乱正则表达式需要一个非捕获组。

最后,从一堆较小的正则表达式构建大型正则表达式的整个方案在 IMO 上的用处非常有限。跟踪各部分之间的交互非常困难,例如哪个部分在哪个组中。 C# 的逐字字符串的另一个优点是它们是多行的,因此您可以利用自由间距模式(又名 /x 或 COMMENTS 模式):

  Regex r = new Regex(@"
(?<GROUPED>
[[{(] # opening bracket
( # group containing:
((\d+(\.\d+)?)|\w+) # number or variable
[*+/-]? # and proceeding operator
)+ # ...one or more times
[]})] # closing bracket
[*+/-]? # and proceeding operator
)
|
(?<UNGROUPED>
((\d+(\.\d+)?)|\w+) # number or variable
[*+/-]? # and proceeding operator
)
",
RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace
);

这不是为了解决您的问题;正如我所说,这不是正则表达式的工作。这只是一些有用的正则表达式技术的演示。

关于c# - 如何在 Regex 中指定匹配模式的优先级?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4425195/

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