一个可能简单的正则表达式

时间:2010-09-07 21:00:17

标签: c# .net regex

关于正则表达式,我是一个完整的新词,并希望帮助使表达式符合以下内容:

 {ValidFunctionName}({parameter}:"{value}")

 {ValidFunctionName}({parameter}:"{value}",
                     {parameter}:"{value}")

 {ValidFunctionName}()

{x}是我要匹配的地方,{parameter}可以是任何$%“$例如$ {value}必须用引号括起来。

ThisIsValid_01(a:"40")

将是“ThisIsValid_01”,“a”,“40”

ThisIsValid_01(a:"40", b:"ZOO")

将是“ThisIsValid_01”,“a”,“40”,“b”,“ZOO”

01_ThisIsntValid(a:"40")

不会返回任何内容

ThisIsntValid_02(a:40)

不会返回任何内容,因为40未用引号括起来。

ThisIsValid_02()

将返回“ThisIsValid_02”

对于我遇到的有效函数名称:“[A-Za-z _] [A-Za-z_0-9] *” 但我不能为我的生活弄清楚如何匹配其余的。 我一直在http://regexpal.com/上玩,试图获得所有条件的有效匹配,但无济于事:(

如果你也很好地解释了正则表达式会很好,所以我可以学习:)

6 个答案:

答案 0 :(得分:2)

编辑:这将有效,使用2个正则表达式。第一个获取函数名称及其中的所有内容,第二个从函数括号内的内容中提取每对参数和值。单个正则表达式无法做到这一点。为空格添加一些[ \t\n\r]*

Regex r = new Regex(@"(?<function>\w[\w\d]*?)\((?<inner>.*?)\)");
Regex inner = new Regex(@",?(?<param>.+?):""(?<value>[^""]*?)""");
string input = "_test0(a:\"lolololol\",b:\"2\") _test1(ghgasghe:\"asjkdgh\")";

List<List<string>> matches = new List<List<string>>();

MatchCollection mc = r.Matches(input);
foreach (Match match in mc)
{
    var l = new List<string>();
    l.Add(match.Groups["function"].Value);
    foreach (Match m in inner.Matches(match.Groups["inner"].Value))
    {
         l.Add(m.Groups["param"].Value);
         l.Add(m.Groups["value"].Value);
    }
    matches.Add(l);
}

(旧)解决方案

(?<function>\w[\w\d]*?)\((?<param>.+?):"(?<value>[^"]*?)"\)

(旧)解释

让我们删除群组抓取,以便更容易理解:\w[\w\d]*?\(.+?:"[^"]?"\)

\w是单词class,它是[a-zA-Z_]的缩写 \d是数字类,它是[0-9]

的缩写
  1. \w[\w\d]*?确保函数开头有有效的单词字符,然后匹配零个或多个字或数字字符。

  2. \(.+?匹配左括号,然后匹配一个或多个任何字符(参数)

  3. :"[^"]*?"\)匹配一个冒号,然后是开头的引号,然后是零或更多的除引号之外的任何字符(对于值),然后是关闭引号和右括号。

  4. 使用反斜杠将转义的方括号(或某些人称之为parens),因为否则它们会捕获组。

    (?<name> )会捕获一些文字。

    每个?*运算符之后的+使它们非贪婪,这意味着它们将匹配最少,而不是最多,文字数量。

    (旧)使用

    Regex r = new Regex(@"(?<function>\w[\w\d]*?)\((?<param>.+?):""(?<value>[^""]*?)""");
    string input = "_test0(aa%£$!:\"lolololol\") _test1(ghgasghe:\"asjkdgh\")";
    
    List<string[]> matches = new List<string[]>();
    
    if(r.IsMatch(input))
    {
        MatchCollection mc = r.Matches(input);
        foreach (Match match in mc)
        matches.Add(new[] { match.Groups["function"].Value, match.Groups["param"].Value, match.Groups["value"].Value });
    }
    

    编辑:现在你已经添加了一个未定义数量的多个参数,我建议你自己创建解析器,而不是使用正则表达式。上面的例子只适用于一个参数,严格来说没有空格。这将使用严格的空格匹配多个参数,但不会返回参数和值:

    \w[\w\d]*?\(.+?:"[^"]*?"(,.+?:"[^"]*?")*\)
    

    只是为了好玩,就像上面一样,但是有了空白:

    \w[\w\d]*?[ \t\r\n]*\([ \t\r\n]*.+?[ \t\r\n]*:[ \t\r\n]*"[^"]*?"([ \t\r\n]*,[ \t\r\n]*.+?[ \t\r\n]*:[ \t\r\n]*"[^"]*?")*[ \t\r\n]*\)
    

    捕获你想要的文本会很难,因为你不知道你将拥有多少个捕获,因此这些正则表达式是不合适的。

答案 1 :(得分:1)

试试这个:

^\s*(?<FunctionName>[A-Za-z][A-Za-z_0-9]*)\(((?<parameter>[^:]*):"(?<value>[^"]+)",?\s*)*\)
  • ^\s*(?<FunctionName>[A-Za-z][A-Za-z_0-9]*)匹配函数名称,^表示行的开头,因此字符串中的第一个字符必须匹配。如果你不需要它,你可以让你删除空格捕获,我只是添加它以使匹配更灵活。
  • 下一组\(((?<parameter>[^:]*):"(?<value>[^"]+)",?)*\)表示捕获括号内的每个参数 - 值对。您必须转义函数的括号,因为它们是正则表达式语法中的符号。

?&lt;&gt;括号内部被命名为捕获组,当它们被库支持时,它们在.NET中,可以更轻松地抓取匹配中的组。

答案 2 :(得分:1)

下面:

\w[\w\d]*\s*\(\s*(?:(\w[\w\d]*):("[^"]*"|\d+))*\s*\)

Visualization of that regex here

答案 3 :(得分:1)

其他人已经给出了一个答案,给出了一个简单的字符串列表,但为了强类型和正确的类结构,我将提供一个正确封装数据的解决方案。

首先,声明两个类:

public class ParamValue         // For a parameter and its value
{
    public string Parameter;
    public string Value;
}
public class FunctionInfo       // For a whole function with all its parameters
{
    public string FunctionName;
    public List<ParamValue> Values;
}

然后进行匹配并填充FunctionInfo s:

的列表

(顺便说一下,我对正则表达式进行了一些修改......它现在将正确匹配标识符,并且它不会将双引号作为每个参数的“值”的一部分。)< / p>

Regex r = new Regex(@"(?<function>[\p{L}_]\w*?)\((?<inner>.*?)\)");
Regex inner = new Regex(@",?(?<param>.+?):""(?<value>[^""]*?)""");
string input = "_test0(a:\"lolololol\",b:\"2\") _test1(ghgasghe:\"asjkdgh\")";

var matches = new List<FunctionInfo>();

if (r.IsMatch(input))
{
    MatchCollection mc = r.Matches(input);
    foreach (Match match in mc)
    {
        var l = new List<ParamValue>();

        foreach (Match m in inner.Matches(match.Groups["inner"].Value))
            l.Add(new ParamValue
            {
                Parameter = m.Groups["param"].Value,
                Value = m.Groups["value"].Value
            });

        matches.Add(new FunctionInfo
        {
            FunctionName = match.Groups["function"].Value,
            Values = l
        });
    }
}

然后,您可以使用FunctionName

等标识符轻松访问该集合
foreach (var match in matches)
{
    Console.WriteLine("{0}({1})", match.FunctionName,
        string.Join(", ", match.Values.Select(val =>
            string.Format("{0}: \"{1}\"", val.Parameter, val.Value))));
}

答案 4 :(得分:0)

对于类似的问题,我总是建议人们不要“找到”单个正则表达式,而是编写多个正则表达式共享工作。

但这是我的快速镜头:

(?<funcName>[A-Za-z_][A-Za-z_0-9]*)
\(
    (?<ParamGroup>
        (?<paramName>[^(]+?)
        :
        "(?<paramValue>[^"]*)"
        ((,\s*)|(?=\)))
    )*
\)

空白是为了更好的可读性。删除它们或设置忽略模式空格的选项。

答案 5 :(得分:0)

此正则表达式传递了所有测试用例:

^(?<function>[A-Za-z][\w]*?)\(((?<param>[^:]*?):"(?<value>[^"]*?)",{0,1}\s*)*\)$

这适用于多个参数,没有参数。它还处理param名称中的特殊字符和逗号后面的空格。可能需要进行一些调整,因为您的测试用例不包括您在文本中指明的所有内容。

请注意,\w通常包含数字,不适合作为函数名称的前导字符。参考:http://www.regular-expressions.info/charclass.html#shorthand