正则表达式与?对于一组词
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
【讨论】:
以上是关于正则表达式与?对于一组词的主要内容,如果未能解决你的问题,请参考以下文章