Ответ 1
Да, это возможно при использовании механизма регулярных выражений, который поддерживает обратные ссылки и условия.
Во-первых, список последовательных чисел можно разложить в список, где каждая пара чисел последовательна:
(?=(?&cons))\d+
(?:,(?=(?&cons))\d+)*
,\d+
Здесь (?=(?&cons))
является заполнителем для предиката, который гарантирует, что два числа являются последовательными. Этот предикат может выглядеть следующим образом:
(?<cons>\b(?:
(?<x>\d*)
(?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4)
|(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8))
(?:9(?= 9*,\g{x}\d (?<y>\g{y}?+ 0)))*
,\g{x}
(?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5)
(?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9)
(?(y)\g{y})
# handle the 999 => 1000 case separately
| (?:9(?= 9*,1 (?<z>\g{z}?+ 0)))+
,1\g{z}
)\b)
Для краткого объяснения второй вопрос, обрабатывающий пары типа 999,1000
, легче понять - есть очень подробное описание того, как он работает в этот ответ, связанный с сопоставлением ^ пь ^ п. Связь между ними заключается в том, что в этом случае нам нужно сопоставить 9^n ,1 0^n
.
Первый случай немного сложнее. Большая часть его обрабатывает простой случай приращения десятичной цифры, которая относительно подробно из-за числа указанных цифр:
(?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4)
|(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8))
(?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5)
(?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9)
Первый блок будет фиксировать, является ли цифра N в группе aN, а второй блок будет использовать условные обозначения, чтобы проверить, какая из этих групп была использована. Если группа aN непустая, следующая цифра должна быть N + 1.
Остальная часть первого случая обрабатывает такие случаи, как 1999,2000
. Это снова попадает в шаблон N 9^n, N+1 0^n
, поэтому это комбинация метода для сопоставления a^n b^n
и увеличения десятичной цифры. Простой случай 1,2
обрабатывается как предельный случай, когда n = 0.
Полное выражение: https://regex101.com/r/zG4zV0/1
В качестве альтернативы предикат (?&cons)
может быть реализован немного более непосредственно, если поддерживаются рекурсивные ссылки подшаблонов:
(?<cons>\b(?:
(?<x>\d*)
(?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4)
|(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8))
(?<y>
,\g{x}
(?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5)
(?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9)
| 9 (?&y) 0
)
# handle the 999 => 1000 case separately
| (?<z> 9,10 | 9(?&z)0 )
)\b)
В этом случае явно выражены две грамматики 9^n ,1 0^n
, n >= 1 и prefix N 9^n , prefix N+1 0^n
, n >= 0.
Полное альтернативное регулярное выражение: https://regex101.com/r/zG4zV0/3