我有一个用户指定的模式:
1998-2010:Make:model:trim:engine
trim
和engine
是可选的,如果存在,我应该抓住它们;如果没有,匹配者至少应该验证YMM。
([0-9]+-*[0-9]+):(.*):(.*):(.*):(.*)
如果所有三个都存在,则匹配,但如何使最后两个且仅两个字段可选?
答案 0 :(得分:8)
?
,“零或一个量词”您可以使用?
来匹配零或一个东西,这是您想要对最后一位做的事情。但是,您的模式需要进行一些修改,使其更像[^:]*
而不是.*
。一些示例代码及其输出如下。我最后得到的正则表达式是:
([^:]*):([^:]*):([^:]*)(?::([^:]*))?(?::([^:]*))?
|-----| |-----| |-----| |-----| |-----|
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 ===
虽然通过使用正则表达式来匹配这种字符串当然是可能的,但似乎可能更容易在:
上拆分字符串并检查你得到多少值。这不一定会进行其他类型的检查(例如,每个字段中的字符),因此在任何非最小的情况下,分裂都不是很有用。
我在另一篇建议使用your comment的帖子中注意到String.split(String)(强调添加):
是的我知道这个功能,但它对我有用,因为我有一个字符串 这是:b:c:d:e:f:g:h ..但我只想将数据分组为 a:b:c:d:e如果有的话和字符串的其余部分作为另一个组
值得注意的是,有一个版本的拆分需要多一个参数,String.split(String,int)。第二个参数是限制,描述为:
limit
参数控制模式的次数 应用因此会影响结果数组的长度。如果 限制 n 大于零,然后将应用模式 大多数 n - 1次,数组的长度不会大于 n ,并且 数组的最后一个条目将包含除最后一个匹配之外的所有输入 分隔符。如果 n 是非正数,则该模式将应用为 尽可能多次,阵列可以有任何长度。如果 n 为零 那么模式将尽可能多地应用于数组 可以有任何长度,尾随空字符串将被丢弃。
这意味着您可以使用split和限制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]
答案 1 :(得分:0)
为什么不跳过正则表达式并使用split(":")
。似乎是直截了当的。从结果数组的长度,您将知道是否提供了模型和引擎等。
String str = "1998-2010:Make:model:trim:engine";
String[] parts = str.split(":");
//parts[0] == Y
//parts[1] == M
//parts[2] == M
//etc
编辑:
正如其他人所提到的,String.split
也使用正则表达式模式。在我的观点中,尽管并不重要。要拥有一个真正的无正则表达式解决方案,请使用apache commons中的StrwingUtils.split
(根本不使用正则表达式):)