可重复的,复杂的正则表达式,带点“。”分隔符

时间:2013-07-19 12:02:05

标签: c# regex

我有一个正则表达式。它包含必需的命名捕获组和一些可选的命名捕获组。它捕获单个匹配并将这些部分解析为我需要的命名组。

除此之外,现在我需要重复它。

基本上,我的正则表达式表示(可能)更长的字符串中的单个原子单元。而不是完全匹配我的正则表达式,目标字符串通常包含正则表达式的重复实例,由点''分隔。字符。

例如,如果这是我的正则表达式捕获的内容:<some match>

实际字符串可能看起来像以下任何一种:

  • <some match>
  • <some match>.<some other match>
  • <some match>.<some other match>.<yet another match>

修改原始正则表达式,考虑重复模式,忽略点的最简单方法是什么?

我不确定它是否真的需要,但这里是我用来捕捉各个片段的正则表达式。同样,我想增强此功能以考虑可选的其他细分。我想让每个段在结果集中显示为另一个“匹配”;

^(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?$

它旨在解析一个类路径,最多包含三个可选的索引访问器。 (即“member.sub_member[0].sub_sub_member[0][1][2]”)

我怀疑答案涉及前瞻或后视,对此我并不完全熟悉。

我目前使用String.Split来分隔字符串段。但我认为如果对正则表达式的增强足够简单,我会跳过额外的Split步骤,并重新使用正则表达式作为验证机制。

修改

作为齿轮中的另一个扳手,我想不允许任何点'。'从字符串的开头或结尾开始的字符。它们应仅作为路径段之间的分隔符存在。

4 个答案:

答案 0 :(得分:2)

你真的不需要使用任何环视。您可以在主模式前放置(^|\.),然后在+后面放置.。这将允许您制作重复的,<index> - 分开的序列。为简单起见,我还建议您将*组合并到一个捕获中(我使用{0,3}匹配任意数量的索引,但您可以轻松地使用(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])*)+$ 仅匹配最多3)。最终的模式是:

var input = "member.sub_member[0].sub_sub_member[0][1][2]";
var pattern = @"(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])*)+$";
var match = Regex.Match(input, pattern);
var parts = 
    (from Group g in match.Groups
     from Capture c in g.Captures
     orderby c.Index
     select c.Value)
    .Skip(1);

foreach(var part in parts)
{
    Console.WriteLine(part);
}

例如:

member
sub_member
0
sub_sub_member
0
1
2

将输出:

^(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3}(?:\.(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3})*$

更新:此模式将确保字符串不能包含任何前导或尾随点。这是一个怪物,但应该有效:

^(?!\.)(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3})*$

或者这个,虽然我确实不得不放弃我的'不看周期'的想法:

{{1}}

答案 1 :(得分:1)

最简单的方法是使用“{”上的string.Split拆分字符串。字符,然后将正则表达式应用于结果数组中的每个元素。一个正则表达式,无论如何都会有一些残酷的表现和潜在的前瞻/背后问题。

答案 2 :(得分:1)

尝试这个野兽:

(?<=^|\.)?((?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?)(?=\.){0,3}$?

以下是一个示例控制台应用程序:

class Program
{
    public static void Main()
    {
        var input = @"member.sub_member[0].sub_sub_member[0][1][2]";
        var matches = Regex.Matches(input, @"(?<=^|\.)?((?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?)(?=\.){0,3}$?");
        foreach (Match match in matches)
        {
            Console.Write("Member: {0} Index {1} Index2: {2} Index3 {3}\r\n", 
                match.Groups["member"].Value,
                match.Groups["index"].Value,
                match.Groups["index2"].Value,
                match.Groups["index3"].Value);
        }
    }
}

答案 3 :(得分:1)

您可以使用\G确保连续的结果和前瞻,以检查模式后面是点还是字符串的结尾:

var pattern = @"(?:^|\G\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)])?(?:\[(?<index3>[0-9]+)])?(?=\.|$)";
来自msdn的

\G “匹配必须从上一场比赛结束的位置开始”