递归RegEx以匹配键和名称

时间:2013-04-10 16:04:45

标签: c# regex recursive-regex

我有字符串["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>.*)";

1 个答案:

答案 0 :(得分:1)

好吧,个人正则表达式分解为:

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

日期:指定的日期字符串,以 - 分隔。不允许任何其他日期格式。注意,前导'#'和尾随'#'不处理,它专门捕获日期,只记录日期

R:行开头OR#,然后格式化替换使其成为一个BIG正则表达式...然后指定另一个#。然后是一个没有错误的条件......并且true也没有做任何事情。

name:捕获剩下的东西。

最终结果,编译成单个正则表达式.... 两个捕获:R和名称。 R:(4份) R-1:匹配行首或# R-2:获取(但绝不是两者)日期或索引 R-3:匹配# R-4:空条件表达式 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个案例。

决赛:最终修改

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

针对替换单独运行它们以获取各个变量,然后重建字符串。