相互包含的正则表达式模式优先级



我想要一个正则表达式,它将帮助我按组('id', 'description', 'category')拆分字符串,其中'id'是整数,'description'是自定义词,'category'是预定义词('C1', 'C2', 'C1 C2', 'C2 C3', 'C1 C2 C3'等)。字符串示例:

  1. 0自定义描述文本C1">
  2. 25自定义描述文本C2">
  3. 100自定义描述文本C1 C2">
  4. 30自定义描述文本C2 C3">
  5. 45自定义描述文本C1 C2 C3">
  6. 45自定义描述文本任何用户自定义类别文本"…..N(大于1000)。2自定义描述文本任何用户定义的类别文本">

一般来说,正则表达式中的替换项是从左到右求值的,因此首先检查最左边的替换项,赋予它们优先级):

(?<id>d{1,3}) (?<description>.+) (?<category>(C1 C2 C3|C1 C2|C2 C3|C2|C1))

但它返回错误的结果-它检测类别= 'C2 C3'在样本#5的情况下(我不明白为什么会发生这种情况)

ps:实际上类别列表是用户定义的列表,我从文件中加载。这可以是任何字符串(实际上不是C1, C2, C3等)。有超过1000+的已知类别…现在我使用这样的解决方案:

  1. 添加所有已知的'categories'到字符串数组

  2. 排序"类别">

    var sortedCategories =分类。OrderByDescending (x =比;

    x.Length) .ToArray ();
  3. 每个类别尝试解析给定的字符串

    forech (var category in sortedCategories){//使用$"(? d {1,3 }) (?.+) (?({ "类别});var match =正则表达式。匹配(givenString面具);if (!match.Success)继续;//找到一个类别。做某事返回;}

这个逻辑是工作的,但它需要太多的时间。我相信我可以定义模式优先级的选项是存在的,但我在正则表达式中很弱,需要帮助:)提前感谢

在我解释为什么在样本#5的情况下检测category = 'C2 C3'之前,让我建议使用
(?<id>d{1,3}) (?<description>.+?) (?<category>(?:C[1-3] ?)+)代替其他选项。(注意(?<description>.+?)中的非贪婪量词+?)

现在,为什么第二个正则表达式在样本#5的情况下检测category = 'C2 C3' -这是因为前面的(?<description>.+)具有贪婪量词+,这使得它尽可能多地匹配,并且对于下面的(?<category>(...))部分,正则表达式引擎只从字符串的末尾尽可能多地回溯,因此它匹配较短的替代。

既然你写了有超过1000+已知的类别它需要很多时间,我不确定这是否可以改善很多保持Regex.Match,因为它需要超过1000个替代品。但是,您可以在不使用循环的情况下测试和比较变体的执行,而是将类别连接到一个模式中:

using System;
using System.Linq;
using System.Text.RegularExpressions;

public class Program
{   public static void Main()
{   string [] categories = { "C1", "C2", "C1 C2", "C2 C3", "C1 C2 C3",
"any user defined category text" };
var sortedCategories = categories.OrderByDescending(x => x.Length).ToArray();
var mask = @"(d{1,3}) (.+?) (" + String.Join("|", sortedCategories) + ")";
string [] givenStrings = { "0 custom description text C1"
, "25 custom description text C2"
, "100 custom description text C1 C2"
, "30 custom description text C2 C3"
, "45 custom description text C1 C2 C3"
, "45 custom description text any user defined category text"
, "2 custom description text any user defined category text"
};
foreach (var givenString in givenStrings)
{
var match = Regex.Match(givenString, mask);
if (match.Success) Console.WriteLine(match.Groups[3]);
}
}
}

如果在mask模式的末尾添加$,则甚至不需要对类别进行排序。

也就是说,你可以没有Regex:

foreach (var category in sortedCategories)
if (givenString.EndsWith(category))
{
//true category found. do something
break;
}

最新更新