C# 从字符串解析函数及其参数的列表

C# 从字符串解析函数及其参数的列表,c#,regex,C#,Regex,我有一个字符串,其中包含一些函数(我知道它们的名称)及其参数,如下所示: 平移(700 210)旋转(-30) 我想在字符串数组中解析它们中的每一个,首先是函数名,然后是参数 我对regex了解不多,到目前为止,我得到了以下信息: MatchCollection matches = Regex.Matches(attribute.InnerText, @"((translate|rotate|scale|matrix)\s*\(\s*(-?\d+\s*\,*\s*)+\))*"); for (i

我有一个字符串,其中包含一些函数(我知道它们的名称)及其参数,如下所示: 平移(700 210)旋转(-30)

我想在字符串数组中解析它们中的每一个,首先是函数名,然后是参数

我对regex了解不多,到目前为止,我得到了以下信息:

MatchCollection matches = Regex.Matches(attribute.InnerText, @"((translate|rotate|scale|matrix)\s*\(\s*(-?\d+\s*\,*\s*)+\))*");
for (int i = 0; i < matches.Count; i++)
{
    Console.WriteLine(matches[i].Value);
}
这对我来说很有用,因为我可以从结果集合的每一行运行另一个正则表达式并获取内容。我不明白的是,为什么在方法之间返回空白行

另外,运行两次正则表达式——一次用于分离方法,一次用于实际解析方法——是一种好方法吗


谢谢

Regex.Matches
将多次匹配整个正则表达式。它为整个对象找到一个匹配项,然后为整个对象找到下一个匹配项

带有
*
的最外层paren表示您愿意接受前面组的零个或多个内容作为匹配项。因此,当它没有发现它们时,它会愉快地返回它们。这不是你的意图。你只想要一个

空白是无害的,但“零或更多”也包括两个。考虑这个字符串,在两个函数之间没有空格:

var text = "translate(700 210)rotate(-30)";
根据你提供的正则表达式,这是一个匹配。你会得到“旋转”和“-30”。如果丢失的空间是一个错误,请检测它并警告用户。如果不打算这样做,请正确解析它

所以,让我们去掉最外层的paren和
*
。为了便于阅读,我们还将命名捕获组

var matches = Regex.Matches(text, @"(?<funcName>translate|rotate|scale|matrix)\s*\(\s*(?<param>-?\s*\d+\s*\,*\s*)+\)");

foreach (Match match in matches)
{
    if (match.Groups["funcName"].Success)
    {
        var funcName = match.Groups["funcName"].Value;
        var param = Int32.Parse(match.Groups["param"].Value);

        Console.WriteLine($"{funcName}( {param} )");
    }
}
var matches=Regex.matches(文本,@“(?平移|旋转|缩放|矩阵)\s*\(\s*(?-?\s*\d+\s*,*\s*)+\”);
foreach(匹配中的匹配)
{
if(match.Groups[“funcName”].Success)
{
var funcName=match.Groups[“funcName”].Value;
var param=Int32.Parse(match.Groups[“param”].Value);
WriteLine($“{funcName}({param})”;
}
}

我还在可选的
-
之后插入了
\s*
,以防万一

我喜欢在字典中使用正则表达式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication56
{
    class Program
    {
        static void Main(string[] args)
        {

            Dictionary<string, string> dict = new Dictionary<string, string>();

            string input = "translate(700 210) rotate(-30)";
            string pattern = @"(?'command'[^\(]+)\((?'value'[^\)]+)\)";

            MatchCollection matches = Regex.Matches(input, pattern);

            foreach(Match match in matches.Cast<Match>())
            {
                dict.Add(match.Groups["command"].Value, match.Groups["value"].Value);
            }

        }
    }

}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Text.RegularExpressions;
命名空间控制台应用程序56
{
班级计划
{
静态void Main(字符串[]参数)
{
Dictionary dict=新字典();
字符串输入=“平移(700 210)旋转(-30)”;
字符串模式=@“(?'command'[^\(]+)\(((?'value'[^\)]+)\)”;
MatchCollection matches=Regex.matches(输入,模式);
foreach(在matches.Cast()中匹配)
{
dict.Add(match.Groups[“command”].Value,match.Groups[“Value”].Value);
}
}
}
}

尝试将您需要的令牌捕获为命名组。这样,您就不必担心它们之间的空格。当我将最后一个
*
更改为
+
时,或者当我完全消除外部参数和
*
时,我不会得到空匹配。最外层的帕伦是不必要的——事实上,比不必要还要糟糕。它尽可能多地匹配你给它的正则表达式。您的正则表达式“零或更多此类内容”碰巧与任何内容都不匹配。谢谢您的回复!我不熟悉正则表达式中的命名组。我知道我可以在模式中“保存”模式以供以后使用,例如(…)(…)\1\2,但是如果这是我需要的,我真的不知道如何在我的模式中实现它。对移除外部括号和*确实解决了空白空间问题。当然-Regex.Matches应该已经查找所有可能的匹配项了!这就解决了问题!我认为这里的行动顺序很重要。如果用户在旋转后想用不同的参数进行第二次翻译呢?我可以将dict改为dictionary。这太棒了!这正是我要问的!我知道命名组现在是如何使用的——这对我来说非常有用,但我并不知道。现在使用match.Groups[“param”]捕获我可以得到所有的参数值!我只剩下一个问题:为什么有一个“?”之前和一个之前?我知道它与0或1次匹配,但在这种情况下它会发生什么变化?我试着把它们去掉,看看会发生什么,正则表达式什么都不匹配?有一种不同的方式<代码>?是表示组名的方式。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication56
{
    class Program
    {
        static void Main(string[] args)
        {

            Dictionary<string, string> dict = new Dictionary<string, string>();

            string input = "translate(700 210) rotate(-30)";
            string pattern = @"(?'command'[^\(]+)\((?'value'[^\)]+)\)";

            MatchCollection matches = Regex.Matches(input, pattern);

            foreach(Match match in matches.Cast<Match>())
            {
                dict.Add(match.Groups["command"].Value, match.Groups["value"].Value);
            }

        }
    }

}