代码之家  ›  专栏  ›  技术社区  ›  Mike Caron

如何将多个子字符串与正则表达式匹配,即使它们是可选的?

  •  1
  • Mike Caron  · 技术社区  · 14 年前

    注意:这是.NET正则表达式。

    type Name(type arg1, type arg2, type arg3)
    

    为了与此匹配,我提出了以下正则表达式:

    ^(\w+)\s+(\w+)\s*\(\s*((\w+)\s+(\w+)(:?,\s+)?)*\s*\)$
    

    这种混乱会产生一个匹配对象,如下所示:

    Group 0: type Name(type arg1, type arg2, type arg3)
        Capture 0: type Name(type arg1, type arg2, type arg3)
    Group 1: type
        Capture 0: type
    Group 2: Name
        Capture 0: Name
    Group 3: type arg3
        Capture 0: type arg1,
        Capture 1: type arg2,
        Capture 2, type arg3
    Group 4: type
        Capture 0: type
        Capture 1: type
        Capture 2: type
    Group 5: arg3
        Capture 0: arg1
        Capture 1: arg2
        Capture 2: arg3
    Group 6:
        Capture 0: ,
        Capture 1: ,
    

    然而,这并不是全部投入。其中一些行可能如下所示:

    type Name(type arg1, type[] arg2, type arg3)
    

    注意arg2之前的括号。

    ^(\w+)\s+(\w+)\s*\(\s*((\w+)\s*(\[\])?\s+(\w+)(:?,\s+)?)*\s*\)$
    

    这会产生如下匹配:

    Group 0: type Name(type arg1, type arg2, type arg3)
        Capture 0: type Name(type arg1, type arg2, type arg3)
    Group 1: type
        Capture 0: type
    Group 2: Name
        Capture 0: Name
    Group 3: type arg3
        Capture 0: type arg1,
        Capture 1: type arg2,
        Capture 2, type arg3
    Group 4: type
        Capture 0: type
        Capture 1: type
        Capture 2: type
    Group 5: []
        Capture0: []
    Group 6: arg3
        Capture 0: arg1
        Capture 1: arg2
        Capture 2: arg3
    Group 7:
        Capture 0: ,
        Capture 1: ,
    

    有什么方法可以将这个捕获与适当的组关联起来,还是我找错了树?

    编辑:
    为了澄清这一点,我并不是在构建一个语言解析器。我正在为脚本语言转换旧的文本api文档,如下所示:

    --- foo object ---
    void bar(int baz)
     * This does something.
     * Remember blah blah blah.
    
    int getFrob()
     * Gets the frob
    

    变成一种新的格式,我可以导出到HTML等。

    编辑mkII:

    m = Regex.Match(line, @"^(\w+)\s+(\w+)\s*\((.*?)\)$");
    if (m.Success) {
    
        if (curMember != null) {
            curType.Add(curMember);
        }
        curMember = new XElement("method");
        curMember.Add(new XAttribute("type", m.Groups[1].Value));
        curMember.Add(new XAttribute("name", m.Groups[2].Value));
    
        if (m.Groups[3].Success) {
            XElement args = new XElement("arguments");
    
            MatchCollection matches = Regex.Matches(m.Groups[3].Value, @"(\w+)(\[\])?\s+(\w+)");
    
            foreach (Match m2 in matches) {
                XElement arg = new XElement("arg");
                arg.Add(new XAttribute("type", m2.Groups[1].Value));
                if (m2.Groups[2].Success) {
                    arg.Add(new XAttribute("array", "array"));
                }
                arg.Value = m2.Groups[3].Value;
    
    
                args.Add(arg);
            }
    
            curMember.Add(args);
        }
    }
    

    首先,它符合 type Name(*) 一部分,当它得到它,它匹配 type Name 在参数部分重复。

    1 回复  |  直到 14 年前
        1
  •  1
  •   Pieter van Ginkel    14 年前

    我要做的是使它成为一个两阶段的解析器。

    首先,我要确定我知道我有什么。在那个阶段,我不关心匹配的组。

    第二个阶段实际上是试图弄清楚这一切。从第一阶段开始,可能很容易得到括号内的所有内容,但是解析参数很困难。所以,从括号内的结果中,你可以把 , 然后逐一分析参数。

    如果这太难了,例如允许多维数组( [,] ),您将创建一个正则表达式,该表达式从参数内的部分获取第一个参数。然后你知道这个论点有多长,从论点中去掉那个部分,剩下三个,等等。

    1. "type Name(type arg1, type[] arg2, type arg3)" => "type arg1, type[] arg2, type arg3"
      
    2. 分析参数:

      "type arg1, type[] arg2, type arg3" => "type", "arg1"
      

      b、 从参数列表中删除已分析参数的长度:

      "type arg1, type[] arg2, type arg3" => ", type[] arg2, type arg3"
      
      
      ", type[] arg2, type arg3".TrimStart(new char[]{ ',', ' ' }) => "type[] arg2, type arg3"
      

      lather, rinse, repeat .