regex необязательная группа захвата JAVA
у меня есть шаблон, где пользователь указывает:
1998-2010:Make:model:trim:engine
trim
и engine
являются необязательными, если присутствует, я должен захватить их; если нет, сопоставитель должен по крайней мере проверить YMM.
([0-9]+-*[0-9]+):(.*):(.*):(.*):(.*)
это соответствует, если все три есть, но как сделать последние два и только два поля необязательными?
2 ответов
используя регулярное выражение и ?
, "нуль или один Квантор"
можно использовать ?
чтобы соответствовать нулю или одному из чего-то, что вы хотите сделать с последним битом. Однако, ваш шаблон должен немного модификация больше нравится [^:]*
, а не .*
. Далее следует пример кода и его вывод. Регулярное выражение, с которым я закончил, было:
([^:]*):([^:]*):([^:]*)(?::([^:]*))?(?::([^:]*))?
|-----| |-----| |-----| |-----| |-----|
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 ===
в то время как это, безусловно, можно сопоставить этот вид строки с помощью регулярного выражения, похоже, что было бы проще просто разделить строку на :
и проверьте, сколько значений вы получите обратно. Это не обязательно делает другие виды проверки (например, символы в каждом поле), поэтому, возможно, разделение не так полезно в любой не минимальной ситуации, мотивирующей это.
Через Строку.split и предельный параметр
я заметил:комментарий на другом сообщение, которое рекомендуется использовать строку.split (String) (Курсив мой):
Да, я знаю эту функцию, но она работает для меня, потому что у меня есть строка это a: b:c:d:e:f:g: h.. но я просто хочу сгруппировать данные как a:b:c:d: e если любой как один и остальная часть строки как другая группа
стоит отметить, что есть версия split, которая принимает еще один параметр,строку.split (String,int). Этот второй параметр-это ограничение, описываемое как:
на
limit
параметр контролирует количество раз, когда шаблон применяется и, следовательно, влияет на длину результирующего массива. Если предел n больше нуля, тогда шаблон будет применяться на большинство n - 1 раз, длина массива не будет больше, чем n, и последняя запись массива будет содержать все введенные за последние совпавшие ограничитель данных. Если n не является положительным, тогда шаблон будет применяться как много раз, насколько это возможно, и массив может иметь любую длину. Если n равна нулю затем шаблон будет применен как можно больше раз, массив может иметь любую длину, и конечные пустые строки будут отброшены.
это означает, что вы можете использовать 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]
Почему бы не пропустить regex и использовать 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
также использует шаблон регулярного выражения. В моем случае это не имеет значения. Чтобы иметь действительно regex-менее решение использовать StrwingUtils.split
из Apache commons (который вообще не использует регулярное выражение):)