代码之家  ›  专栏  ›  技术社区  ›  Blam

可能是简单的regex表达式

  •  0
  • Blam  · 技术社区  · 14 年前

    当涉及到regex时,我是一个完全的新手,我想帮助您在以下方面创建一个匹配的表达式:

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

    其中x是我想要匹配的,参数可以是任何$%“$例如,值必须用引号括起来。

    ThisIsValid_01(a:"40")
    

    将是“thisis valid_01”,“a”,“40”

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

    将是“这是有效的”,“A”,“40”,“B”,“动物园”

    01_ThisIsntValid(a:"40")
    

    什么都不退

    ThisIsntValid_02(a:40)
    

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

    ThisIsValid_02()
    

    将返回“thisis valid_02”

    对于一个有效的函数名,我遇到了:“[a-z a-z\[a-z a-z_0-9]*” 但我一辈子都想不出如何与其他人相匹配。 我一直在玩 http://regexpal.com/ 尝试获取所有条件的有效匹配,但无效:(

    如果你也能解释一下regex,我会很高兴的,这样我就可以学习了:)

    6 回复  |  直到 14 年前
        1
  •  1
  •   Timwi    14 年前

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

    首先,声明两个类:

    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:

    (顺便说一下,我对正则表达式做了一些细微的修正……现在,它将正确匹配标识符,并且不包括双引号作为每个参数的__value_157;的一部分。)

    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))));
    }
    
        2
  •  2
  •   Callum Rogers    14 年前

    编辑: 这将有效,使用2个regex。第一个获取函数名及其内部的所有内容,第二个从函数括号内的内容中提取每对参数和值。你不能用一个正则表达式来完成这个操作。添加一些 [ \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. :"[^"]*?"\) 匹配冒号,然后是左引号,然后是除引号(用于值)之外的零个或多个字符,然后是右引号和右括号。

    括号(或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 });
    }
    

    编辑: 现在您添加了一个未定义数量的多个参数,我建议您创建自己的解析器,而不是使用regex。上面的示例只适用于一个参数,并且严格禁止使用空白。这将使用严格的空白匹配多个参数,但不会返回参数和值:

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

    只是为了好玩,就像上面所说的,但是使用WhiteSpace:

    \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]*\)
    

    捕获您想要的文本将是困难的,因为您不知道将要捕获多少,因此regex不适合。

        3
  •  1
  •   Benjamin Anderson    14 年前

    试试这个:

    ^\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>[^"]+)",?)*\) 表示捕获括号内的每个参数值对。您必须转义函数的括号,因为它们是regex语法中的符号。

    这个?<gt;括号内称为捕获组,当库支持时,就像在.NET中一样,这样可以更容易地捕获匹配项中的组。

        4
  •  1
  •   Nightfirecat peSHIr    13 年前

    在这里:

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

    Visualization of that regex here .

        5
  •  0
  •   Scordo    14 年前

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

    但这是我的快速镜头:

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

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

        6
  •  0
  •   Timwi    14 年前

    此regex通过所有测试用例:

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

    这在多个参数上工作,没有参数。它还处理参数名中的特殊字符和逗号后的空白。可能需要进行一些调整,因为您的测试用例并没有涵盖您在文本中指出的所有内容。

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