Регулярные выражения — проверка последовательностей

govnoproger.ru > интернет > Регулярные выражения — проверка последовательностей

Интересную тему увидел, решил попробовать. Можете поиграть если интересно, 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 по символу «;» , дальше будет гораздо легче и не будет пустот.

Рекомендую:

20.4.2012 | последняя редакция: 20.04.2012 |