我有一个正则表达式。它包含必需的命名捕获组和一些可选的命名捕获组。它捕获单个匹配并将这些部分解析为我需要的命名组。
除此之外,现在我需要重复它。
基本上,我的正则表达式表示(可能)更长的字符串中的单个原子单元。而不是完全匹配我的正则表达式,目标字符串通常包含正则表达式的重复实例,由点''分隔。字符。
例如,如果这是我的正则表达式捕获的内容:<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步骤,并重新使用正则表达式作为验证机制。
修改
作为齿轮中的另一个扳手,我想不允许任何点'。'从字符串的开头或结尾开始的字符。它们应仅作为路径段之间的分隔符存在。
答案 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
“匹配必须从上一场比赛结束的位置开始”