正则表达式与?对于一组词

Posted

技术标签:

【中文标题】正则表达式与?对于一组词【英文标题】: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。 【参考方案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

【讨论】:

以上是关于正则表达式与?对于一组词的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式

C#:正则表达式不匹配一组单词

正则表达式总结

re 正则表达式

对于正则表达式模式,如何确定与模式匹配的最长字符串的长度?

一组匹配中国大陆手机号码的正则表达式