订购一组正则表达式模式或获取最大的正则表达式匹配
Posted
技术标签:
【中文标题】订购一组正则表达式模式或获取最大的正则表达式匹配【英文标题】:Order a set of regex patterns OR Get the biggest regex match 【发布时间】:2017-01-01 05:27:15 【问题描述】:给定一个正则表达式模式的数字列表,按该数值中的最后 4 个数字对它们进行排序。
我有一个正则表达式(电话号码)模式列表,我正在尝试按最后 4 个字符对它们进行排序。以下是电话号码示例:
8062
\+13066598273
4083100
408320[0-3]
408320[4-6]
752[234569]
\+13066598305
8059
我想按最后 4 个数字对这些数字重新排序,以便最终得到如下列表:
4083100
408320[0-3]
408320[4-6]
752[234569]
8059
8062
\+13066598273
\+13066598305
现在,如果我的模式只是数字,我可以在 SQL 或我的 MVC C# 项目中轻松地对它们进行排序。在 SQL 中,我可以使用 ORDER BY RIGHT(pattern, 4),或者在 C# MVC 中,我可以使用 patterns = patterns.OrderByDescending(s => s.Substring( ...等等...)).
模式有点困难。括号算作字符,因此按最后 4 个字符排序也不起作用。
C#、MVC 或 SQL 中是否有任何内置实用程序可让我将正则表达式模式转换为最大可能匹配?
给定一个正则表达式模式,返回与我的条件匹配的最大可能匹配正则表达式。例如,如果我有模式 4[12]00[1-3],我将有 6 个可能的结果:41001、41002、41003、42001、42002、42003。然后我可以获得最大的数字,并使用用于在我的原始正则表达式列表中排序。 正则表达式不包含 * 或 + 等可能导致无限组合的特殊字符。 可能有一个 C# 库完全符合我的要求,对正则表达式模式字符串进行排序。编辑:
我已经接受了 Diego 的回答,但我花了一些时间来理解它。对于其他想知道它在做什么的读者,这就是我认为 Diego 正在做的事情:
-
创建一个整数范围,从 9999 开始,一直到 0。[9999]、[9998]、[9997]...[0]。
用单个字符替换字符串的正则表达式部分。例如,“500[1-5]”会变成“500X”,或者“20[1-9]00[89]”会变成“20X00X”,以此类推。
获取“最后”4 个字符 + 正则表达式字符的长度。
var len = lastNChars + pattern.Length - Regex.Replace(pattern, @"\[[^\]]+\]", "X").Length;
因此对于模式 20[1-9]00[89],上述公式转换为“len = 4 + 13 - 6”,即 11。
使用上面的 len 变量,得到一个表示电话号码“最后”4 个数字的子字符串,即使是正则表达式字符。原始字符串 = "20[1-9]00[89]",而新的子字符串 = "[1-9]00[89]"(现在 20 没有了)
枚举数组值并将其与子字符串正则表达式模式进行比较。 [9999] 不匹配正则表达式模式,[9998] 不匹配... [9997]不匹配……啊哈! 9009场比赛!我得到的第一场比赛是最大可能的正则表达式匹配,这就是我想要的。 因此,每个正则表达式模式都已转换为其最大可能的匹配模式。现在我们可以使用 C#/LINQ/其他内置方法,这些方法可以为我们按这些子正则表达式匹配进行排序!感谢上帝,我只处理数字。如果我试图对实际上是单词/具有字母字符的正则表达式模式进行排序,那将更加困难,并且该数组会更大(我认为)。
【问题讨论】:
【参考方案1】:如果不枚举并测试它们,很难找到与正则表达式匹配的示例字符串。我也不认为您将能够找到对正则表达式进行排序的 C# 库。但是,对于不包含量词的特殊模式(例如[0-9]+
或[3-6]4
),您可以解决此问题,如下所示:
const int lastNChars = 4;
var patterns = new string[]@"8062", @"\+13066598273", @"4083100",
@"408320[0-3]", @"408320[4-6]", @"752[234569]",
@"\+13066598305", @"8059";
var range = Enumerable.Range(0, (int) Math.Pow(10, lastNChars))
.Reverse().ToArray();
var sortedPatterns = patterns.OrderBy(pattern=>
var len = lastNChars + pattern.Length
- Regex.Replace(pattern, @"\[[^\]]+\]", "X").Length;
// Get the biggest number in range that matches this regex:
var biggestNumberMatched = range.FirstOrDefault(x =>
Regex.IsMatch(x.ToString(new String('0', lastNChars)),
pattern.Substring(pattern.Length - len, len))
);
return biggestNumberMatched;
).ToArray();
之后,sortedPatterns
包含所需的输出。
【讨论】:
这就是我要找的,非常感谢!现在我正在为我自己的 MVC 项目调整它。我也傻了眼,发现我的数字列表中包含少于 4 位数字的数字。我可能会暂时将它们强制转换为 4 位数字,例如将“40”变成“0040”。【参考方案2】:这是一个解决方案,感谢 Matt Hamilton 来自 question:
var pList = new List<string>()
"01233[0-3]", "12356[1-3]", "55555[7-9]"
;
var paired =
pList.Select(x =>
new KeyValuePair<int, string>
(Int32.Parse(new String((new String(x.Where(Char.IsDigit).Reverse().ToArray()))
.Substring(0, 4).Reverse().ToArray())), x));
var pairedOrdered = paired.OrderByDescending(x => x.Key);
foreach(var kvp in pairedOrdered)
Console.WriteLine("Key: 0 Value: 1", kvp.Key, kvp.Value);
输出:
键:5613 值:12356[1-3]
键:5579 值:55555[7-9]
键:3303 值:01233[0-3]
【讨论】:
以上是关于订购一组正则表达式模式或获取最大的正则表达式匹配的主要内容,如果未能解决你的问题,请参考以下文章