【问题标题】:Regular expression with variable number of groups?具有可变组数的正则表达式?
【发布时间】:2011-06-28 10:58:12
【问题描述】:

是否可以创建具有可变数量组的正则表达式?

例如运行后...

Pattern p = Pattern.compile("ab([cd])*ef");
Matcher m = p.matcher("abcddcef");
m.matches();

...我想要类似的东西

  • m.group(1) = "c"
  • m.group(2) = "d"
  • m.group(3) = "d"
  • m.group(4) = "c"

(背景:我正在解析一些数据行,其中一个“字段”正在重复。我想避免这些字段出现matcher.find 循环。)


正如 @Tim Pietzcker 在 cmets 中指出的那样,perl6.NET 具有此功能。

【问题讨论】:

    标签: java regex


    【解决方案1】:

    根据documentation,Java正则表达式不能这样做:

    捕获的与 a 关联的输入 组始终是 最近匹配的组。如果一个 第二次评估组 因为量化然后它 先前捕获的值(如果有), 如果第二个将被保留 评估失败。匹配字符串 "aba" 反对表达式 (a(b)?)+, 例如,将第二组设置为 “乙”。所有捕获的输入都被丢弃 在每场比赛开始时。

    (强调)

    【讨论】:

      【解决方案2】:

      您可以使用 split 将您需要的字段放入一个数组并循环遍历它。

      http://download.oracle.com/javase/1,5.0/docs/api/java/lang/String.html#split(java.lang.String)

      【讨论】:

        【解决方案3】:

        我没有使用过 java 正则表达式,但对于许多语言来说,答案是:没有。

        捕获组似乎在解析正则表达式时创建,并在匹配字符串时填充。表达式(a)|(b)(c) 具有三个捕获组,只有其中一个或两个可以填充。 (a)* 只有一个组,解析器在匹配后离开组中的最后一个匹配项。

        【讨论】:

        • .NET 有 captures,因此您可以访问重复子组的单个匹配项。
        • @Tim,啊,看那个。这正是我所追求的(但在 Java 中)。
        【解决方案4】:
        Pattern p = Pattern.compile("ab(?:(c)|(d))*ef");
        Matcher m = p.matcher("abcdef");
        m.matches();
        

        应该做你想做的。

        编辑:

        @aioobe,我现在明白了。你希望能够做类似语法的事情

        A    ::== <Foo> <Bars> <Baz>
        Foo  ::== "foo"
        Baz  ::== "baz"
        Bars ::== <Bar> <Bars>
                | ε
        Bar  ::== "A"
                | "B"
        

        并拉出Bar的所有个人匹配项。

        不,使用java.util.regex 无法做到这一点。您可以递归并在Bars 的匹配上使用正则表达式,或者使用像ANTLR 这样的解析器生成器并将副作用附加到Bar

        【讨论】:

        • 嗯,这不是可变数量的组。那总是两组。也许我简化了我的例子有点too。 (澄清问题。)
        • @aioobe,我编辑了这篇文章来解决你澄清的问题。
        【解决方案5】:

        我认为回溯会抑制这种行为,并说/([\S\s])/ 在其分组累积状态中对圣经之类的东西的影响。即使可以做到,输出也是不可知的,因为这些组将失去位置意义。最好在全局意义上对同类进行单独的正则表达式并将其存放到数组中。

        【讨论】:

          【解决方案6】:

          我刚刚遇到了非常相似的问题,并设法做到了“可变数量的组”,但是结合了一个 while 循环和重置匹配器。

              int i=0;
              String m1=null, m2=null;
          
              while(matcher.find(i) && (m1=matcher.group(1))!=null && (m2=matcher.group(2))!=null)
              {
                  // do work on two found groups
                  i=matcher.end();
              }
          

          但这是我的问题(有两个重复

              Pattern pattern = Pattern.compile("(?<=^ab[cd]{0,100})[cd](?=[cd]{0,100}ef$)");
              Matcher matcher = pattern.matcher("abcddcef")
              int i=0;
              String res=null;
          
              while(matcher.find(i) && (res=matcher.group())!=null)
              {
                  System.out.println(res);
                  i=matcher.end();
              }
          

          您无法使用*+ 指定任意重复长度,因为前瞻和后瞻必须具有可预测的长度。

          【讨论】:

            【解决方案7】:

            如果您会遇到合理的最大匹配组数:

            "ab([cd])?([cd])?([cd])?([cd])?([cd])?([cd])?([cd])?([cd])?ef"
            

            此示例适用于 0 - 8 个匹配项。我承认这是丑陋的,不适合人类阅读。

            【讨论】:

            • "ab" + "([cd])?".repeat(8) + "ef" 稍微好一点。
            猜你喜欢
            • 1970-01-01
            • 2014-03-05
            • 1970-01-01
            • 2023-04-01
            • 2011-06-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多