递归RegEx匹配键和名称

本文关键字:RegEx 递归 | 更新日期: 2023-09-27 18:08:42

我有字符串["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"

敏锐的眼睛能看到我错过的东西吗?


Final Solution As I need It

结果证明我不需要递归群。我只需要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>.*)";

递归RegEx匹配键和名称

单个正则表达式分解为:

Index:捕获单个正数或负数。(-, 0或1代表,后面跟着一个或多个数字)

date:指定的日期字符串,以"-"分隔。不允许任何其他日期格式。注意,前面的"#"和后面的"#"不被处理,它专门捕获日期,并且只有日期

R:开始的行或#,然后格式化替换,使其成为一个大正则表达式…然后指定另一个#。然后是一个没有假的条件…而true也没有任何作用

name:捕捉剩余内容

最终结果,编译成单个正则表达式....两个捕获:R和name。R:(4个部分)R-1:匹配行首或#R-2:获取日期或索引中的一个(但不能同时获取)R-3:匹配#r4:空条件表达式Name:匹配剩下的

问题似乎是您没有匹配索引和日期

最终编辑,工作正则表达式

听我说,这东西太恶心了。你必须考虑到所有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: Final Edit

有一种方法可以使用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}(.*)";

分别运行它们以获取单个变量,然后重建字符串。