Операторы ?, +, и * являются по умолчанию "жадными". Таким образом, они пытаются соответствовать такому большому вводу насколько возможно. Иногда это не то, чего мы хотим. Рассмотрим следующий список пап римских пятого столетия:
popesArray = [
"Pope Anastasius I 399-401",
"Pope Innocent I 401-417",
"Pope Zosimus 417-418",
"Pope Boniface I 418-422",
"Pope Celestine I 422-432",
"Pope Sixtus III 432-440",
"Pope Leo I the Great 440-461",
"Pope Hilarius 461-468",
"Pope Simplicius 468-483",
"Pope Felix III 483-492",
"Pope Gelasius I 492-496",
"Pope Anastasius II 496-498",
"Pope Symmachus 498-514"
]
Первая попытка на регулярное выражение анализирует название (без порядкового номера либо модификатор) и годы каждого папы римского может быть следующим:
Который распадается как:
/ | Pope | (.*) | (?: .*)? | ([0-9]+) | - | ([0-9]+) | / |
начните выражение | Папа римский | фиксируйте некоторые символы | группа некадра: пространство и некоторые символы | фиксируйте число | - | фиксируйте число | конец выражения |
Мы надеемся, что тогда первая группа кадра будет просто именем Папы Римского в каждом примере, но, как выясняется, он захватывает слишком много ввода. Например первый папа римский разбивается следующим образом:
/ | Pope | (.*) | (?: .*)? | ([0-9]+) | - | ([0-9]+) | / |
начните выражение | Папа римский | Anastasius I | 399 | - | 401 | конец выражения |
Ясно первая группа кадра фиксирует слишком большой ввод. Мы только хотим фиксировать Anastasius, и модификаторы должны быть зафиксированы второй группой кадра. Еще один способ состоит в том, что первая группа кадра должна должны охватывать небольшой ввод насколько возможно, чтобы все еще соответствовать. В этом случае это было бы все до следующего пространства. Java регулярные выражения позволяют нам сделать это, используя "reluctant" версии *, + и ? операторов. Для того чтобы сделать один из этих операторов reluctant, просто добавьте ? после его (сделать *?, +? и ??). Таким образом, наши новые регулярные выражения будет:
/Pope (.*?)(?: .*)? ([0-9]+)-([0-9]+)/
Теперь взглянем на наши новые регулярные выражения в самых сложных вариантах, один перед Папой Hilarius (реальный шутник), разбивается следующим образом:
/ | Pope | (.*?) | (?: .*)? | ([0-9]+) | - | ([0-9]+) | / |
начните выражение | Папа римский | Leo | I the Great | 440 | - | 461 | конец выражения |
Который является тем, что мы хотим.
Так что для проверки, мы будем использовать код:
popesArray = [
"Pope Anastasius I 399-401",
"Pope Innocent I 401-417",
"Pope Zosimus 417-418",
"Pope Boniface I 418-422",
"Pope Celestine I 422-432",
"Pope Sixtus III 432-440",
"Pope Leo I the Great 440-461",
"Pope Hilarius 461-468",
"Pope Simplicius 468-483",
"Pope Felix III 483-492",
"Pope Gelasius I 492-496",
"Pope Anastasius II 496-498",
"Pope Symmachus 498-514"
]
myClosure = {
myMatcher = (it =~ /Pope (.*?)(?: .*)? ([0-9]+)-([0-9]+)/);
if (myMatcher.matches())
println(myMatcher[0][1]+": "+myMatcher[0][2]+" to "+myMatcher[0][3]);
}
popesArray.each(myClosure);
Попробуйте этот код с оригинальным регулярным выражением, чтобы видеть сломанный вывод.