我有字符串,["02-03-2013#3rd Party Fuel", "-1#Archived", "2#06-23-2013#Newswire"]
,我想分解成几个部分。这些字符串以日期和索引键为前缀,并包含一个名称。
我设计了一个正确匹配每个键的 RegEx
。但是,如果我想一举匹配索引键、日期键和名称。只找到第一个键。递归组似乎没有像我预期的那样工作。
private const string INDEX_KEY_REGEX = @"(?<index>-?\d+)";
private const string DATE_KEY_REGEX = @"(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-\d{4})";
private const string KEY_SEARCH_REGEX = @"(?<R>(?:^|(?<=#))({0})#(?(R)))(?<name>.*)";
private string Name = "2#06-23-2013#Newswire"
... = Regex.Replace(
Name,
String.Format(KEY_SEARCH_REGEX, INDEX_KEY_REGEX + "|" + DATE_KEY_REGEX),
"${index}, ${date}, ${name}"
);
// These are the current results for all strings when set into the Name variable.
// Correct Result: ", 02-03-2013, 3rd Party Fuel"
// Correct Result: "-1, , Archived"
// Invalid Result: "2, , 06-23-2013#Newswire"
// Should be: "2, 06-23-2013, Newswire"
敏锐的眼睛能看出我错过了什么吗?
我需要的最终解决方案
原来我不需要递归组。我只需要 0 到多个序列。这是完整的 RegEx
。
(?:(?:^|(?<=#))(?:(?<index>-?\d+)|(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-(\d{2}|\d{4})))#)*(?<name>.*)
并且,分段的 RegEx
private const string INDEX_REGEX = @"(?<index>-?\d+)";
private const string DATE_REGEX = @"(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-(\d{2}|\d{4}))";
private const string KEY_WRAPPER_REGEX = @"(?:^|(?<=#))(?:{0})#";
private const string KEY_SEARCH_REGEX = @"(?:{0})*(?<name>.*)";
最佳答案
好吧,各个正则表达式分解为:
索引:捕获单个正数或负数。 (-、0 或 1 个代表,后跟一位或多位数字)
date:指定的日期字符串,以-分隔。不允许任何其他日期格式。注意,不处理前导 '#' 和尾随 '#',它专门捕获日期,并且只捕获日期
R:行首或 #,然后是格式替换,使其成为一个大正则表达式……然后是另一个 #,已指定。然后是一个没有 false 的条件...并且 true 也不会做任何事情。
name: 捕获剩下的任何东西。
最终结果,编译成一个正则表达式.... 两次捕获:R 和名称。 R:(4 部分) R-1:匹配行首或# R-2:获取其中一个(但绝不能同时获取)日期或索引 R-3:匹配# R-4:空条件表达式 名称:匹配剩下的任何内容。
问题似乎是您没有同时匹配索引和日期
最终编辑,工作正则表达式
请耐心等待,这东西很讨厌。您必须考虑所有 4 种可能性,否则它不会匹配所有可能的情况。我想不出任何方法来概括它。
(?:(?<index>-?\d+(?!\d-))#(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4})|(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4})#(?<index>-?\d+)|(?!-?\d+#)(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4})|(?<index>-?\d+)(?!#(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4}))#(?<name>.*)
丑陋的,我知道。它有 4 个初始条件。
1a) capture <index>#<date> OR
1b) capture <date>#<index> OR
1c) capture <index> only, as long as its not followed by a date OR
1d) capture <date> only, as long as its not preceded by an index
...
2) match but ignore #
3) capture <name>
适用于所有 4 种情况。
Final:最终编辑
有一种方法可以使用 3 个正则表达式而不是 1 个来做到这一点,这最终可能会更干净。
//note: index MIGHT be preceeded by, and is ALWAYS followed by, a #
indexRegex = @"((?=#)?(?<!\d|-)-?\d+(?=#))";
//same with date
dateRegex = @"((?=#)?(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-\d{4}(?=#))";
//then name
nameRegex = @"(?:.*#){1,2}(.*)";
针对替换分别运行它们以获取各个变量,然后重建字符串。
关于c# - 递归正则表达式以匹配键和名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15930917/