Регулярные выражения — проверка последовательностей
Интересную тему увидел, решил попробовать. Можете поиграть если интересно, preg_match_all online находится тут.
У вас имеются последовательности вида:
//правильные последовательности
23:6,5,24,6;
234:34,21;
3:657,98,6,43,232,2,4,6;
//неправильные последовательности
234:,;
24:34,24,43,34:43;
После двоеточия, чисел через запятую может быть сколько угодно, но они должны заканчиваться символом «;» . Также после двоеточия должно быть хотя-бы одно число. Каждая последовательность начинается с новой строчки.
Вам нужно проверить их валидность. Мало ли двоеточие забыли поставить, или ещё там чо-то не туда влепили. Чтобы не запутаться в сложном выражении я поэтапно разбил его на мелкие.
С чего начать?
Начать лучше с преобразования двойных символов в одинарные — но это не всегда необходимо.
Напишем неправильные последовательности (я их написал) — они помогут нам в тесте, далее нужно определить минимум последовательности. Например в нашем случае минимальная последовательность будет например содержать 0:1;
Запишем как: /\d+:\d+;/
Следующий шаг
Теперь наш пример выглядит 0:1,24,32;
Тут уже есть последовательность — это запятая после которой идёт число (,24) и так до бесконечности, пока не наткнётся на «;» . Запишем это как:
/\d+:\d+(,\d+)*;/
Казалось бы всё верно, однако после запуска мы видим что оно глотает неправильную пятую последовательность:
Array ( [0] => Array ( [0] => 23:6,5,24,6; [1] => 234:34,21; [2] => 3:657,98,6,43,232,2,4,6; [3] => 34:43; < - неправильно ) [1] => Array ( [0] => ,6 [1] => ,21 [2] => ,6 [3] => ) )
Почему это происходит очевидно — не было точки с запятой — поэтому строку штудировало дальше.
Мы можем ограничить выражение так: /^\d+:\d+(,\d+)*;/m
Теперь всё верно, однако на деле условия могут быть намного сложнее.
Давайте изменим правила последовательности — теперь у нас нет символа перевода строки:
23:6,5,24,6;234:34,21;3:657,98,6,43,232,2,4,6;234:,;24:34,24,43,34:43;
Вот так вот одной строкой, и наше выражение становится абсолютно неверным из-за символа начала строки.
Вернёмся к нашему неправильному выражению: /\d+:\d+(,\d+)*;/
Что делать?
Дальше начинается страшная вещь. Нам нужно принять во внимание что последовательность заканчивается символом «;» , однако после точки с запятой должно быть число.
Наше выражение принимает вид: /\d+:\d+(,\d+)*;(?=\d+)/
Где (?=\d+)
означает позитивный просмотр вперёд. Позитивный или негативный просмотры вперёд или назад, с отрицание и без, всегда смотрят, но при этом не включают в конечный результат.
Это ещё не конец. Внимательный читатель наверное обратил внимания что наше регулярное выражение не сработает если последовательность будет одна. Учтём это.
Добавление условия
Диктую условие: Если число то ничего не делаем, если нет, то это конец строки.
(?(?!$)(?=\d+)|$))
Итого наше выражение:
/\d+:\d+(,\d+)*;(?(?!$)(?=\d+)|$)/
Результат выполнения:
Array ( [0] => Array ( [0] => 23:6,5,24,6; [1] => 234:34,21; [2] => 3:657,98,6,43,232,2,4,6; [3] => 34:43; < - снова та-же ошибка ) [1] => Array ( [0] => ,6 [1] => ,21 [2] => ,6 [3] => ) )
Это регулярное выражение правильно возьмет одну последовательность.
Неправильную пятую последовательность отсеим при помощи позитивного просмотра назад с самого начала. Т.к. наши последовательности не могут начинаться на запятую или какие либо числа.
Условие:
(?(?<=[,0-9])сюдаНичегоНеПишем|СдесьОстальноеВыражение)
Итого финал:
/(?(?<=[,0-9])|\d+:\d+(,\d+)*;(?(?!$)(?=\d+)|$))/
Результат:
Array ( [0] => Array ( [0] => 23:6,5,24,6; [1] => 234:34,21; [2] => 3:657,98,6,43,232,2,4,6; [3] => [4] => [5] => [6] => [7] => [8] => [9] => [10] => [11] => [12] => [13] => [14] => [15] => [16] => [17] => [18] => [19] => [20] => [21] => ) [1] => Array ( [0] => ,6 [1] => ,21 [2] => ,6 [3] => [4] => [5] => [6] => [7] => [8] => [9] => [10] => [11] => [12] => [13] => [14] => [15] => [16] => [17] => [18] => [19] => [20] => [21] => ) )
Образуются пустоты в массиве, однако они не являются проблемой.
Другое решение:
Сделать explode по символу «;» , дальше будет гораздо легче и не будет пустот.