我认为你不能使用递归,但是通过不同的输入模式表示,你可以使用子组。请注意,我在这个例子中使用了命名捕获来稍微减少混淆:
var test = @"{{test_data}}
{{!test_data}}
{{test_data1&&!test_data2&&test_data3}}
{{test_data1&&!test_data2 fail test_data3}}
{{test_data1&&test_data2||!test_data3}}";
// (1:!)(2:word)(3:||&&)(4:repeat)
var matches = Regex.Matches(test, @"\{{2}(?:(?<exc>!?)(?<word>\w+))(?:(?<op>\|{2}|&{2})(?<exc2>!?)(?<word2>\w+))*}{2}");
foreach (Match match in matches)
{
Console.WriteLine("Match: {0}", match.Value);
Console.WriteLine(" exc: {0}", match.Groups["exc"].Value);
Console.WriteLine(" word: {0}", match.Groups["word"].Value);
for (int i = 0; i < match.Groups["op"].Captures.Count; i++)
{
Console.WriteLine(" op: {0}", match.Groups["op"].Captures[i].Value);
Console.WriteLine(" exc2: {0}", match.Groups["exc2"].Captures[i].Value);
Console.WriteLine("word2: {0}", match.Groups["word2"].Captures[i].Value);
}
}
这个想法是无条件地读取每组的第一个单词,然后可能作为单独的组带有子捕获读取N个(|| 或 &&)(可选!)(单词)
的组合。
示例输出:
Match: {{test_data}}
exc:
word: test_data
Match: {{!test_data}}
exc: !
word: test_data
Match: {{test_data1&&!test_data2&&test_data3}}
exc:
word: test_data1
op: &&
exc2: !
word2: test_data2
op: &&
exc2:
word2: test_data3
Match: {{test_data1&&test_data2||!test_data3}}
exc:
word: test_data1
op: &&
exc2:
word2: test_data2
op: ||
exc2: !
word2: test_data3
请注意,行
{{test_data1&&!test_data2 fail test_data3}}
不符合语法规则,因此不是结果组的一部分。
因此,您可以从匹配结构中以相同的方式构建所需的结果。
foreach (Match match in matches)
{
var sb = new StringBuilder();
sb.Append(match.Groups["exc"].Value).Append("mystring.").Append(match.Groups["word"].Value);
for (int i = 0; i < match.Groups["op"].Captures.Count; i++)
{
sb.Append(' ').Append(match.Groups["op"].Captures[i].Value).Append(' ');
sb.Append(match.Groups["exc2"].Value).Append("mystring.").Append(match.Groups["word2"].Value);
}
Console.WriteLine("Result: {0}", sb.ToString());
}
{{2}(?:(!?)(\w*)(\|{2}|&{2})?|(.?))(!?)(\w*)}{2}
- Ferhat Sayan