正则表达式可选组捕获 JAVA
我有一个模式,其中用户指定:
1998-2010:Make:model:trim:engine
trim
并且是可选的,如果存在,我应该捕获它们;如果不是,匹配器至少应验证 YMM。engine
([0-9]+-*[0-9]+):(.*):(.*):(.*):(.*)
如果所有三个字段都存在,则此字段匹配,但是如何使最后两个且只有两个字段可选?
我有一个模式,其中用户指定:
1998-2010:Make:model:trim:engine
trim
并且是可选的,如果存在,我应该捕获它们;如果不是,匹配器至少应验证 YMM。engine
([0-9]+-*[0-9]+):(.*):(.*):(.*):(.*)
如果所有三个字段都存在,则此字段匹配,但是如何使最后两个且只有两个字段可选?
?
您可以使用来匹配零个或其中一个,这就是您要对最后一个位执行的操作。但是,您的模式需要稍作修改才能更像 而不是 .下面是一些示例代码及其输出。我最终得到的正则表达式是:?
[^:]*
.*
([^:]*):([^:]*):([^:]*)(?::([^:]*))?(?::([^:]*))?
|-----| |-----| |-----| |-----| |-----|
a a a a a
|-----------||-----------|
b b
每个都匹配一个非冒号序列(尽管您希望修改第一个序列以匹配年份),并且是一个非捕获组(因此它以 开头),并且匹配零次或一次(因为它具有最终量词)。这意味着第四个和第五个字段是可选的。示例代码显示,在存在三个、四个或五个字段的情况下,此模式匹配,如果存在五个以上或少于三个字段,则此模式不匹配。a
b
?:
?
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class QuestionMarkQuantifier {
public static void main(String[] args) {
final String input = "a:b:c:d:e:f:g:h";
final Pattern p = Pattern.compile( "([^:]*):([^:]*):([^:]*)(?::([^:]*))?(?::([^:]*))?" );
for ( int i = 1; i <= input.length(); i += 2 ) {
final String string = input.substring( 0, i );
final Matcher m = p.matcher( string );
if ( m.matches() ) {
System.out.println( "\n=== Matches for: "+string+" ===" );
final int count = m.groupCount();
for ( int j = 0; j <= count; j++ ) {
System.out.println( j + ": "+ m.group( j ));
}
}
else {
System.out.println( "\n=== No matches for: "+string+" ===" );
}
}
}
}
=== No matches for: a ===
=== No matches for: a:b ===
=== Matches for: a:b:c ===
0: a:b:c
1: a
2: b
3: c
4: null
5: null
=== Matches for: a:b:c:d ===
0: a:b:c:d
1: a
2: b
3: c
4: d
5: null
=== Matches for: a:b:c:d:e ===
0: a:b:c:d:e
1: a
2: b
3: c
4: d
5: e
=== No matches for: a:b:c:d:e:f ===
=== No matches for: a:b:c:d:e:f:g ===
=== No matches for: a:b:c:d:e:f:g:h ===
虽然使用正则表达式当然可以匹配这种字符串,但似乎只需拆分字符串并检查返回的值可能更容易。这不一定能进行其他类型的检查(例如,每个字段中的字符),因此,在任何非最小情况下,拆分可能都不是那么有用。:
我注意到您对另一篇建议使用String.split(String)的帖子的评论(着重号是后加的):
是的,我知道这个函数,但它对我有用,因为我有一个字符串,它是a:b:c:d:e:f:g:h.。但我只想将数据分组为a:b:c:d:e(如果有的话)作为一个,字符串的其余部分作为另一个组
值得注意的是,有一个版本的split需要另一个参数,String.split(String,int)。。第二个参数是限制,描述为:
该参数控制应用模式的次数,因此会影响结果数组的长度。如果限制 n 大于零,则模式将最多应用 n - 1 次,数组的长度将不大于 n,数组的最后一个条目将包含除最后匹配的分隔符之外的所有输入。如果 n 为非正数,则模式将尽可能多地应用,并且数组可以具有任何长度。如果 n 为零,则模式将尽可能多地应用,数组可以具有任何长度,并且将丢弃尾随的空字符串。
limit
这意味着您可以使用 split 和 limit 6 从输入中获取最多五个字段,并且您将剩余的输入作为最后一个字符串。您仍然需要检查是否至少有3个元素,以确保有足够的输入,但总而言之,这似乎可能更简单一些。
import java.util.Arrays;
public class QuestionMarkQuantifier {
public static void main(String[] args) {
final String input = "a:b:c:d:e:f:g:h";
for ( int i = 1; i <= input.length(); i += 2 ) {
final String string = input.substring( 0, i );
System.out.println( "\n== Splits for "+string+" ===" );
System.out.println( Arrays.toString( string.split( ":", 6 )));
}
}
}
== Splits for a ===
[a]
== Splits for a:b ===
[a, b]
== Splits for a:b:c ===
[a, b, c]
== Splits for a:b:c:d ===
[a, b, c, d]
== Splits for a:b:c:d:e ===
[a, b, c, d, e]
== Splits for a:b:c:d:e:f ===
[a, b, c, d, e, f]
== Splits for a:b:c:d:e:f:g ===
[a, b, c, d, e, f:g]
== Splits for a:b:c:d:e:f:g:h ===
[a, b, c, d, e, f:g:h]
为什么不跳过正则表达式并使用 .似乎直截了当。从结果数组的长度,您将知道是否提供了模型和引擎等。split(":")
String str = "1998-2010:Make:model:trim:engine";
String[] parts = str.split(":");
//parts[0] == Y
//parts[1] == M
//parts[2] == M
//etc
编辑:正如其他人所提到的,也使用正则表达式模式。在我看来,这并不重要。要从apache共享资源(根本不使用正则表达式)使用真正的无正则表达式解决方案:)String.split
StrwingUtils.split