代码之家  ›  专栏  ›  技术社区  ›  richardtallent

要在CDL上重复捕获吗?

  •  1
  • richardtallent  · 技术社区  · 15 年前

    我有一些这样的数据:

    @"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 回复  |  直到 15 年前
        1
  •  1
  •   Alan Moore Chris Ballance    15 年前

    以下是一个纯替换解决方案:

    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");
    

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

        2
  •  0
  •   dtb    15 年前

    如果你能用linq做,为什么要用regex?

    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
    
        3
  •  0
  •   Ahmad Mageed    15 年前

    既然你强调了对regex的需求,这里有一个适合你的解决方案。

    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+)? 部分,它是可选的,因为 ? 放在它后面。最后,模式的整个部分被封闭在一个组中,该组必须至少匹配一次 (?:...)+ 但没有被捕获,因为我们只捕获我们感兴趣的部分。
        4
  •  0
  •   Tim Pietzcker    15 年前

    你可以搜索

    ^(\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]+(.+)$ 匹配逗号、空格,然后匹配后面的内容,直到行尾。只有当行中仍然包含需要拆分的内容时,才会匹配。