我有一个正则表达式,如下:
(?<one-1>cat)|(?<two-2>dog)|(?<three-3>mouse)|(?<four-4>fish)
当我尝试在.Net应用程序中使用此模式时,它失败了,因为组名称中包含“ - ”。
因此,作为一种解决方法,我尝试使用两个正则表达式,第一个:
(?<A>cat)|(?<Be>dog)|(?<C>mouse)|(?<D>fish)
会将我正在寻找的原始案例与我能控制的群组名称相匹配 然后,我打算使用正则表达式中的正则表达式组名,如下所示:
(?<A>one-1)|(?<Be>two-2)|(?<C>three-3)|(?<D>four-4)
我会这样做,通过找到与此模式匹配的字符串并确定组名是否相等。
我知道这似乎有点费解。感谢您提供的任何帮助。
答案 0 :(得分:3)
?<one-1>
不起作用,因为-
用于平衡组:
删除先前定义的组名称2的定义,并在组名称1中存储先前定义的名称2组与当前组之间的间隔。如果未定义组名称2,则匹配回溯。因为删除name2的最后一个定义会显示name2的先前定义,所以此构造允许将group name2的捕获堆栈用作计数器,以跟踪嵌套构造(如括号)。在此构造中,name1是可选的。您可以使用单引号而不是尖括号;例如,(?'name1-name2')。
您无法转义该减号,因此您必须使用其他分隔符。
答案 1 :(得分:1)
尝试使用下划线而不是破折号。当我将原始正则表达式更改为:
(?<one_1>cat)|(?<two_2>dog)|(?<three_3>mouse)|(?<four_4>fish)
我能够使用群组[“one_1”]。值来获得匹配的群组。
编辑:示例:
string pattern = "(?<one_1>cat)|(?<two_2>dog)|(?<three_3>mouse)|(?<four_4>fish)";
string[] inputs = new[]{"cat", "horse", "dog", "dolphin", "mouse", "hamster", "fish"};
string[] groups = new[]{"one_1", "two_2", "three_3", "four_4"};
foreach(string input in inputs)
{
Match oMatch = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
Console.WriteLine("For input: {0}", input);
foreach(string group in groups)
{
Console.WriteLine("Group {0}:\t{1}", group, oMatch.Groups[group].Value);
}
Console.WriteLine("----------");
}
在开头使用破折号会导致它找不到组名。我假设它使用与.NET其余部分相同的变量命名规则,因此如果您不能将其用作合法变量名,请不要将其用作组名。
答案 2 :(得分:0)
下面的内容是什么?
string[,] patterns = {
{ "one-1", "cat" },
{ "two-2", "dog" },
{ "three-3", "mouse" },
{ "four-4", "fish" },
};
var regex = buildRegex(patterns);
string[] tests = { "foo", "dog", "bar", "fish" };
foreach (var t in tests) {
var m = regex.Match(t);
Console.WriteLine("{0}: {1}", t, reportMatch(regex, m));
}
输出
foo: no match dog: two-2 = dog bar: no match fish: four-4 = fish
首先,我们通过转义组名并将它们与模式组合来构建Regex
实例。任何非单词字符都将替换为序列_nnn_
,其中 nnn 是其UTF-32值。
private static Regex buildRegex(string[,] inputs)
{
string regex = "";
for (int i = 0; i <= inputs.GetUpperBound(0); i++) {
var part = String.Format(
"(?<{0}>{1})",
Regex.Replace(inputs[i,0], @"([\W_])", new MatchEvaluator(escape)),
inputs[i,1]);
regex += (regex.Length != 0 ? "|" : "") + part;
}
return new Regex(regex);
}
private static string escape(Match m)
{
return "_" + Char.ConvertToUtf32(m.Groups[1].Value, 0) + "_";
}
对于匹配,.NET库没有给我们一个简单的方法来获取组的名称,所以我们必须采用另一种方式:对于每个组名,我们检查该组是否匹配,如果是这样的话,它的名称是unescape并让调用者知道名称和捕获的子字符串。
private static string reportMatch(Regex regex, Match m)
{
if (!m.Success)
return "no match";
foreach (var name in regex.GetGroupNames()) {
if (name != "0" && m.Groups[name].Value.Length > 0)
return String.Format(
"{0} = {1}",
Regex.Replace(name, @"_(\d+)_",
new MatchEvaluator(unescape)),
m.Groups[name].Value);
}
return null;
}
private static string unescape(Match m)
{
return Char.ConvertFromUtf32(int.Parse(m.Groups[1].Value));
}
答案 3 :(得分:0)
我不清楚您希望最终结果是什么,但以下内容会将值映射到原始组名。从那里你可以确定如何继续。
尝试一下:
var map = new Dictionary<string, string>()
{
{"A", "one-1"},
{"B", "two-2"},
{"C", "three-3"},
{"D", "four-4"}
};
string[] inputs = { "cat", "dog", "mouse", "fish", "bird" };
string pattern = "(?<A>cat)|(?<B>dog)|(?<C>mouse)|(?<D>fish)";
Regex rx = new Regex(pattern);
foreach (string input in inputs)
{
Match m = rx.Match(input);
if (m.Success)
{
string groupName = rx.GetGroupNames()
.Where(g => g != "0" && m.Groups[g].Value != "")
.Single();
Console.WriteLine("Match: {0} -- Group name: {1} -- Corresponds to: {2}",
input, groupName, map[groupName]);
}
else
{
Console.WriteLine("Failed: {0}", input);
}
}
Regex.GetGroupNames method提供了一种从模式中提取组名的简便方法。当引用组的值不匹配时,它将返回一个空字符串。这种方法背后的想法是遍历(LINQ通过)每个组名称并检查是否存在匹配而忽略默认的“0”组。如果匹配,那就是我们追求的群体。