可重复的复杂正则表达式,带点'';分隔符

本文关键字:带点 分隔符 正则表达式 复杂 | 更新日期: 2023-09-27 18:23:59

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

不过,现在我需要重复一遍。

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

例如,如果这是我的正则表达式捕获的内容:<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来分隔字符串段。但我认为,如果regex的增强足够简单,我会跳过额外的Split步骤,并将regex重新用作验证机制。

编辑:

作为齿轮上的一个额外扳手,我想不允许任何点字符串开头或结尾的字符。它们只能作为路径段之间的分隔符存在。

可重复的复杂正则表达式,带点'';分隔符

您实际上不需要使用任何环视。您可以在主模式前面放一个(^|'.),然后在主模式后面放一个+。这将允许您制作一个重复的、以.分隔的序列。为了简单起见,我还建议您将<index>组组合成一个捕获(我使用*来匹配任何数量的索引,但您也可以同样轻松地使用{0,3}来匹配最多3个索引)。最终的模式是:

(?:(?:^|'.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:'[(?<index>[0-9]+)'])*)+$

例如:

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})*$

最简单的方法可能是在'.'上使用string.Split拆分字符串字符,然后将正则表达式应用于生成的数组中的每个元素。Regex这么长时间的表现会很残酷,而且可能会出现前瞻性/落后性问题。

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

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

from msdn:with 'G"比赛必须从上一场比赛结束的位置开始"

试试这个野兽:

(?<=^|'.)?((?<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);
        }
    }
}