Список совпадений целых чисел с использованием регулярных выражений

Можно ли сопоставить список разделенных запятыми десятичных целых чисел, где целые числа в списке всегда увеличиваются на единицу?

Они должны соответствовать:

0,1,2,3
8,9,10,11
1999,2000,2001
99,100,101

Они не должны совпадать (во всей полноте - последние две имеют соответствующие подпоследовательности):

42
3,2,1
1,2,4
10,11,13

Ответ 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