【问题标题】:Regex with ? for a set of words正则表达式与?对于一组词
【发布时间】:2021-07-25 01:06:44
【问题描述】:

我想为 NAME;NAME;NAME 以及 NAME;NAME;NAME;NAME 提供一个正则表达式,其中 NAME 的第四次出现是可选的。

我有一个正则表达式作为 (.+);(.+);(.+) 匹配第一个模式但不匹配第二个。我试着玩?但它不适用于 (.+);(.+);(.+)(;(.+))? 基本上,我想将第四个 (.+) 实现为零或一次。

【问题讨论】:

  • . 可以表示/匹配任何字符,包括;,这会使事情复杂化。代替.*,您可以使用; 的否定,例如[^;]+。无论如何,正确的解决方案取决于您的真正目标是什么(我们不知道)。也许更简单的选择是拆分 ; 或使用 CSV 解析器和 ; 作为分隔符。
  • 您也可以使用(([^;]+);){2,4}([^;]+)(([^;]+);){2,4} 表示(([^;]+);) 至少会出现 2 次但少于 4 次。
  • 我想出了 ([^;]+;)?(.+);(.+);(.+) --> 它的问题在于 NAME;NAME;NAME组将是 2,3 和 4。这样做的任何更清洁的方式可能会有所帮助。根据 cmets 的另一个是 ([^;]+);([^;]+);([^;]+);?([^;]+)?
  • 如果某些String 匹配它或从String 中提取groups,您需要正则表达式来获取boolean 结果?
  • 从字符串中提取分组。也更愿意坚持使用 DOT。

标签: java regex regex-group


【解决方案1】:

你可以使用惰性量词+?。示例:

    private static final Pattern pattern = Pattern.compile("((\\w+);?)+?");

    public void extractGroups(String input) {
        var matcher = pattern.matcher(input);
        while (matcher.find()) {
            System.out.println(matcher.group(2));
        }
    }

输入"FIRST;SECOND;THIRD;FOURTH" 给出

FIRST
SECOND
THIRD
FOURTH

输入"FIRST;SECOND;THIRD" 给出

FIRST
SECOND
THIRD

惰性量词用于匹配最短的String。如果您在while 循环中重复调用它,您将获得所有匹配项。 此外,您最好使用\\w 来表示数学单词,因为. 还包括; 符号;

【讨论】:

    【解决方案2】:

    您可以使用regex(.+);\1;\1(?:;\1)?

    演示:

    import java.util.stream.Stream;
    
    public class Main {
        public static void main(String args[]) {
            // Test
            Stream.of(
                        "NAME;NAME;NAME", 
                        "NAME;NAME;NAME;NAME",
                        "NAME;NAME;NAME;",
                        "NAME;NAME;NAMES",
                        "NAME;NAME;NAME;NAME;NAME"
            ).forEach(s -> System.out.println(s + " => " + s.matches("(.+);\\1;\\1(?:;\\1)?")));
        }
    }
    

    输出:

    NAME;NAME;NAME => true
    NAME;NAME;NAME;NAME => true
    NAME;NAME;NAME; => false
    NAME;NAME;NAMES => false
    NAME;NAME;NAME;NAME;NAME => false
    

    正则表达式的解释:

    • \1 匹配第一个捕获组最近匹配的相同文本。
    • ?: 使 (?:;\1) 成为非捕获组。
    • ? 使之前的令牌成为可选的

    【讨论】:

      【解决方案3】:

      使用您展示的示例,请尝试以下操作。

      第一种解决方案:

      ^(?:([^;]*);){2,3}\1$
      

      Online demo for 1st solution

      说明:为上述添加详细说明。

      ^(?:        ##Matching value from starting of the value here.
        ([^;]*);  ##Creating 1st capturing group which has everything till ; in it, followed by ;.
      ){2,3}      ##Looking for 2 to 3 occurrences of it.
      \1$         ##Again matching 1st capturing group value at the end here.
      


      第二个解决方案:

      ^([^;]*)(;)(?:\1\2){1,2}\1$
      

      Online demo for 2nd solution

      说明:为上述添加详细说明。

      ^([^;]*)  ##checking from starting of value, a capturing group till value of ; is coming here.
      (;)       ##Creating 2nd capturing group which has ; in it.
      (?:       ##Creating a non-capturing group here.
      \1\2      ##Matching 1st and 2nd capturing group here.
      ){1,2}    ##Closing non-capturing group here, with occurrences of 1 to 2.    
      \1$   ##Matching 1st capturing group value here at the end of value.
      

      【讨论】:

        【解决方案4】:

        使用.+匹配包括;在内的任何字符的1+次

        如果你想匹配由 ; 分隔的 3 或 4 个组如果不包括它,您可以在模式末尾使用带有可选组的 negated character class [^;]+

        ^([^;]+);([^;]+);([^;]+)(?:;([^;]+))?$
        
        • ^ 字符串开始
        • ([^;]+);([^;]+);([^;]+) 捕获组 1、2 和 3 匹配除 ; 之外的任何字符
        • (?:非捕获组
          • ;([^;]+) 匹配 ; 并捕获除第 4 组中的 ; 之外的任何字符
        • )? 关闭组并使其成为可选
        • $字符串结束

        Regex demo


        如果中间的部分不能包含;,你也可以使用 split 并计算部分的数量。

        String arr[] = { "NAME;NAME;", "NAME;NAME;NAME", "NAME;NAME;NAME;NAME", "NAME;NAME;NAME;NAME;NAME" };
        
        for (String s  : arr) {
            String [] parts = s.split(";");
            if (parts.length == 3 || parts.length == 4) {
                System.out.println(s);
            }
        }
        

        输出

        NAME;NAME;NAME
        NAME;NAME;NAME;NAME
        

        【讨论】:

          猜你喜欢
          • 2021-07-31
          • 1970-01-01
          • 2011-08-13
          • 1970-01-01
          • 2011-10-12
          • 1970-01-01
          • 2021-06-18
          • 1970-01-01
          • 2014-03-02
          相关资源
          最近更新 更多