可重复的复杂正则表达式,带点'';分隔符
本文关键字:带点 分隔符 正则表达式 复杂 | 更新日期: 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);
}
}
}