我想使用正则表达式来验证类似这样的字符串:
foo.bar=123.baz=456.qux=789.urr
(其中123
,456
和789
是占位符的任意数字,但是foo
,bar
,baz
,{{1 }和qux
是文字文字,而不是占位符。我需要单独捕获urr
/ bar
/ baz
的值,以便我使用命名捕获组
问题是qux
,bar=a
和baz=b
完全是可选的,可以按任何顺序出现。所以我的正则表达式需要接受这些有效:
qux=c
...但拒绝这些无效:
foo.urr
foo.bar=123.urr
foo.qux=123.bar=456.urr
foo.baz=123.bar=456.qux=789.urr
我的正则表达式代码现在是这样的:
foo.bar=123.bar=456.urr
foo.qux=123.baz=456.qux=789.urr
我的表达式使用const String Bar = @"(?<bar>bar=(\d)+)";
const String Baz = @"(?<baz>baz=(\d)+)";
const String Qux = @"(?<qux>qux=(\d)+)";
const String Regex = @"^foo\.((" + Bar + "|" + Baz + "|" + Qux + @")\.)*urr$";
以任意顺序允许可选的*
,Bar
和Baz
命名组,但它也允许它们多次出现,不应该被允许。
我知道我可以用Qux
表达式来强制它,但是将来这些元素的数量会随着时间的推移而扩展,并且无法进行硬编码。
我可以在原始问题中使用更好的示例,但n!
,bar
和baz
的值都有自己的子表达式,例如qux
接受十六进制数字,bar
接受十进制数字,baz
仅接受字母字符,因此无效:
qux
答案 0 :(得分:1)
您可以使用以下正则表达式:
^foo(?:\.(?<name>bar|baz|qux)=(?<value>\d+)(?!.*\k<name>))*.urr$
示例代码:
string[] lines = {
"foo.urr",
"foo.bar=123.urr",
"foo.qux=123.bar=456.urr",
"foo.baz=123.bar=456.qux=789.urr",
"foo.bar=123.bar=456.urr",
"foo.qux=123.baz=456.qux=789.urr"
};
foreach (string line in lines)
{
Match m = Regex.Match(line, @"^foo(?:\.(?<name>bar|baz|qux)=(?<value>\d+)(?!.*\k<name>))*.urr$");
Console.WriteLine("{0} : {1}", line, m.Success);
if (m.Success)
{
for (int i = 0; i < m.Groups["name"].Captures.Count; i++)
Console.WriteLine("{0} = {1}",
m.Groups["name"].Captures[i].Value,
m.Groups["value"].Captures[i].Value);
}
}
示例输出:
foo.urr : True
foo.bar=123.urr : True
bar = 123
foo.qux=123.bar=456.urr : True
qux = 123
bar = 456
foo.baz=123.bar=456.qux=789.urr : True
baz = 123
bar = 456
qux = 789
foo.bar=123.bar=456.urr : False
foo.qux=123.baz=456.qux=789.urr : False
<强>更新强>
每个小组都必须有一个名字。然后我们可以做出以下原则:如果给出A,B,C,则ABC重复3次将给出所有可能的组合,即(A?B?C?){3}
。然后我们只需要负向前瞻,这样如果它已经匹配就没有其他匹配的A.
^foo(?:(?:.bar=(?<bar>\d+)(?!.*\.bar))?(?:.baz=(?<baz>\d+)(?!.*\.baz))?(?:.qux=(?<qux>\d+)(?!.*\.qux))?){0,3}.urr$
示例代码:
string[] lines = {
"foo.urr",
"foo.bar=123.urr",
"foo.qux=123.bar=456.urr",
"foo.baz=123.bar=456.qux=789.urr",
"foo.bar=123.bar=456.urr",
"foo.qux=123.baz=456.qux=789.urr"
};
foreach (string line in lines)
{
Match m = Regex.Match(line, @"^foo((?:.bar=(?<bar>\d+)(?!.*\.bar))?(?:.baz=(?<baz>\d+)(?!.*\.baz))?(?:.qux=(?<qux>\d+)(?!.*\.qux))?){0,3}.urr$");
Console.WriteLine("{0} : {1}", line, m.Success);
if (m.Success)
{
Group bar = m.Groups["bar"];
if (bar.Success)
Console.WriteLine("bar = {0}", bar.Value);
Group baz = m.Groups["baz"];
if (baz.Success)
Console.WriteLine("baz = {0}", baz.Value);
Group qux = m.Groups["qux"];
if (qux.Success)
Console.WriteLine("qux = {0}", qux.Value);
}
}
输出:
foo.urr : True
foo.bar=123.urr : True
bar = 123
foo.qux=123.bar=456.urr : True
bar = 456
qux = 123
foo.baz=123.bar=456.qux=789.urr : True
bar = 456
baz = 123
qux = 789
foo.bar=123.bar=456.urr : False
foo.qux=123.baz=456.qux=789.urr : False
答案 1 :(得分:0)
正如您所要求的示例,这是一种以正确格式捕获所有字符串的方法:
^foo\.(?:([a-zA-Z]+)\=(\d+)\.)*urr$
有两个编号的捕获组,因此在您的示例foo.baz=123.bar=456.qux=789.urr
中,匹配将如下所示:
0: baz, bar, qux
1: 123, 456, 789
在代码中处理此问题相对简单。例如:
var reg = new Regex(@"^foo\.(?:([a-zA-Z]+)\=(\d+)\.)*urr$");
var test = "foo.baz=123.bar=456.qux=789.urr";
var match = reg.Match(test);
return match.Groups[0].Captures.Count == match.Groups[0].Captures.Cast<Capture>().Distinct();
如果没有您描述的重复字符串,则返回true,否则返回false。
作为代码处理的另一个例子,您还可以很容易地将两个捕获集合转换为使用所描述技术的字典,例如:create a dictionary using 2 lists using LINQ
另请注意,如果要在正则表达式中指定键,可以将[a-zA-Z]+
替换为要匹配的单个字符串,如baz|bar|qux
。或者,您也可以在代码中检查它。