正则表达式在CDL上重复捕获?

时间:2010-05-26 15:52:12

标签: c# .net regex

我有这种形式的一些数据:

@"Managers Alice, Bob, Charlie
Supervisors Don, Edward, Francis"

我需要像这样的扁平输出:

@"Managers Alice
Managers Bob
Managers Charlie
Supervisors Don
Supervisors Edward
Supervisors Francis"

上面的实际“职称”可以是任何一个单词,也没有可以使用的离散列表。

替换为\r\n非常容易,第一次替换也是如此:

Replace (^|\r\n)(\S+\s)([^,\r\n]*),\s
With $1$2$3\r\n$2

但是捕获其他名称并应用相同的前缀是我今天无法想象的。有什么建议吗?

我正在寻找一系列一个或多个RegEx.Replace()调用,在C#中没有任何LINQ或过程代码,这当然是微不足道的。实现不是直接的在C#代码中,我正在配置一个通用的解析工具,该工具使用一系列.NET正则表达式来转换来自各种来源的传入数据,以用于多种用途。

4 个答案:

答案 0 :(得分:1)

这是一个纯粹的替换解决方案:

string s = @"Managers Alice, Bob, Charlie
Supervisors Don, Edward, Francis";
Regex r = new Regex(@"(?:^\w+)?( \w+)(?<=^(\w+)\b.*)[,\r\n]*",
    RegexOptions.Multiline);
string s1 = r.Replace(s0, "$2$1\r\n");

在匹配每个名称后,lookbehind返回到当前行的开头以捕获标题。 (?:^\w+)?[,\r\n]*仅用于消耗您不想保留的字符串部分。

答案 1 :(得分:0)

为什么要使用正则表达式,如果你可以使用LINQ?

string s = "Managers Alice, Bob, Charlie\r\nSupervisors Don, Edward, Francis";

var result =
    from line in s.Split(new string[] { "\r\n" }, StringSplitOptions.None)
    let parts = line.Split(new char[] { ' ' }, 2)
    let title = parts[0]
    let names = parts[1]
    from name in names.Split(new char[] { ',' })
    select title.Trim() + " " + name.Trim();

string.Join("\r\n", result)

Managers Alice
Managers Bob
Managers Charlie
Supervisors Don
Supervisors Edward
Supervisors Francis

答案 2 :(得分:0)

既然你强调了正则表达式的必要性,那么这个解决方案应该适合你。

string input = @"Managers Alice, Bob, Charlie
Supervisors Don, Edward, Francis";
string pattern = @"(?<Title>\w+)\s+(?:(?<Names>\w+)(?:,\s+)?)+";

foreach (Match m in Regex.Matches(input, pattern))
{
    Console.WriteLine("Title: {0}", m.Groups["Title"].Value);
    foreach (Capture c in m.Groups["Names"].Captures)
    {
        Console.WriteLine(c.Value);
    }

    Console.WriteLine();
}

主要概念是使用命名的“标题”组来存储作业标题并在以后引用它们。名称存储在捕获集合中。只有在数据格式正确的情况下才能使用该模式,如样本数据中所示。

模式细分如下:(?<Title>\w+)\s+(?:(?<Names>\w+)(?:,\s+)?)+

  • (?<Title>\w+)\s+ - 匹配第一个空格之前的标题,并将其放入指定的Title组中。必须至少有一个空格。
  • (?:(?\ w +)(?:,\ s +)?)+ - 名称通过Names部分存储在(?<Names>\w+)组中,逗号和至少一个空格通过(?:...)部分匹配(但未使用(?:,\s+)?后未捕获)并且它是可选的,因为?位于其后面。最后,模式的整个部分被包含在一个必须至少匹配一次(?:...)+的组中,但由于我们只捕获了我们感兴趣的部分,因此不会被捕获。

答案 3 :(得分:0)

您可以搜索

^(\w+)[ \t]+(\w+),[ \t]+(.+)$

并将所有内容替换为

\1 \2\r\n\1 \3

您需要将两次应用于您的示例,如果经理列表增长到四,则需要三次等等。

所以,在C#中:

resultString = Regex.Replace(subjectString, @"^(\w+)[ \t]+(\w+),[ \t]+(.+)$", @"$1 $2\r\n$1 $3", RegexOptions.Multiline);

说明:

^:匹配行的开头

(\w+)[ \t]+:匹配任意数量的alnum字符,捕获匹配项;匹配以下空格

(\w+):匹配下一个“字”,然后

,[ \t]+(.+)$匹配一个逗号,空格,然后是后续的任何内容,直到该行的结尾。只有当该行仍包含需要拆分的内容时,才会匹配。