我想要一个正则表达式,它将帮助我按组('id', 'description', 'category')拆分字符串,其中'id'是整数,'description'是自定义词,'category'是预定义词('C1', 'C2', 'C1 C2', 'C2 C3', 'C1 C2 C3'等)。字符串示例:
- 0自定义描述文本C1">
- 25自定义描述文本C2">
- 100自定义描述文本C1 C2">
- 30自定义描述文本C2 C3">
- 45自定义描述文本C1 C2 C3">
- 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+的已知类别…现在我使用这样的解决方案:
添加所有已知的'categories'到字符串数组
排序"类别">
var sortedCategories =分类。OrderByDescending (x =比;
x.Length) .ToArray ();每个类别尝试解析给定的字符串
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;
}