0

我想要一个正则表达式,它可以帮助我按组('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))

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

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

  1. 将所有已知的“类别”添加到字符串数组

  2. 排序“类别”

    var sortedCategories = categories.OrderByDescending(x => x.Length).ToArray();

  3. 对于每个类别,尝试解析给定的字符串

    foresch(var category in sortedCategories) { //使用 $"(?\d{1,3}) (?.+) (?({category})" var match = Regex.Match(givenString, mask); if ( !match.Success) continue; //找到真正的类别。做一些事情 return; }

这个逻辑是有效的,但它需要很多时间。我相信我可以定义模式优先级的选项是存在的,但我在正则表达式方面很弱,需要帮助:) 在此先感谢

4

2 回答 2

0

在我解释为什么它在示例 #5 的情况下检测到 category = 'C2 C3'之前,让我建议使用
(?<id>\d{1,3}) (?<description>.+?) (?<category>(?:C[1-3] ?)+)而不是交替使用。(注意 中的非贪婪量词+?(?<description>.+?)

现在,为什么第二个正则表达式 在样本 #5 的情况下检测类别 = 'C2 C3' - 那是因为前面(?<description>.+)有贪婪的量词+,导致它尽可能匹配,并且对于以下 (?<category>(...))部分,正则表达式引擎从最后回溯字符串仅在必要时进行,因此它匹配较短的替代方案。

于 2021-03-06T17:43:47.140 回答
0

既然您写了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;
                }
于 2021-03-07T10:50:27.710 回答