Повторные группы захвата обычно захватывают только последнюю итерацию . Это верно как для Kotlin, так и для Java, поскольку в языках нет никакого метода, который бы отслеживал каждый стек групп захвата.
Что вы можете сделать в качестве обходного пути, это сначала проверка всей строки по определенному шаблону, которому должна соответствовать строка, а затем либо извлечение, либо разбиение строки на части.
Для текущего сценария вы можете использовать
val text = "A-3M+2D"
if (text.matches("""A(?:[+-]\d{1,2}[YMD])*""".toRegex())) {
val results = text.split("(?=[-+])".toRegex())
println(results)
}
// => [A, -3M, +2D]
См. Демоверсию Kotlin
Здесь
text.matches("""A(?:[+-]\d{1,2}[YMD])*""".toRegex())
гарантирует, что вся строка соответствует A
, а затем 0 или более вхождений +
или -
, 1 или 2 цифры с последующими Y
, M
или D
.split("(?=[-+])".toRegex())
разделяет текст с пустой строкой прямо перед -
или +
.
Детали шаблона
^
- неявно в .matches()
- начало строки A
- A
подстрока (?:
- начало группы без захвата : [+-]
- класс символов согласование +
или -
\d{1,2}
- от одной до двух цифр [YMD]
- класс символов, соответствующий Y
или M
или D
)*
- конец группы без захвата, повторить 0 или более раз (из-за *
квантификатор) \z
- подразумевается в matches()
- конец строки.
При разбиении нам просто нужно найти местоположения до -
или +
, поэтому мы используем положительное значение lookahead , (?=[-+])
, соответствующее позиция, за которой сразу следует +
или -
. Это непотребляющий шаблон, сопоставленные +
или -
не добавляются к значению соответствия.
Другой подход с одним регулярным выражением
You может также использовать регулярное выражение \G
для проверки формата строки сначала в начале строки и только начинать сопоставлять последовательные подстроки, если эта проверка прошла успешно:
val regex = """(?:\G(?!^)[+-]|^(?=A(?:[+-]\d{1,2}[YMD])*$))[^-+]+""".toRegex()
println(regex.findAll("A-3M+2D").map{it.value}.toList())
// => [A, -3M, +2D]
См. другой Kotlin demo и regex demo .
Подробности
(?:\G(?!^)[+-]|^(?=A(?:[+-]\d{1,2}[YMD])*$))
- либо конец предыдущего успешного совпадение и затем +
или -
(см. \G(?!^)[+-]
) или (|
) начало строки, за которой следует A
, а затем 0 или более вхождений +
/ -
, 1 или 2 цифры и затем Y
, M
или D
до конца строки (см. ^(?=A(?:[+-]\d{1,2}[YMD])*$)
) [^-+]+
- 1 или более символов, отличных от -
и +
. Нам не нужно быть здесь слишком осторожными, так как оглядывающая сторона сделала тяжелую работу в начале строки.