Поиск подстроки с определенным набором символов в нужном порядке

127
22 марта 2022, 20:40

Приветствую и сразу хочу подчеркнуть, что не интересует какое-либо другое решение, кроме как одна единственная операция с помощью функции preg_match()! И в данном случае, не важно почему.

Итак, поиск производится в пути URL, например: /some/path/123-c456-c7-9/. Забегая вперёд скажу, что в вышеуказанном примере нам нужна подстрока 123-c456-c7-9.
Необходимо найти ту часть пути, которая может состоять из групп, разделённых дефисом, а каждая группа может состоять только из цифр и символа "c" в нижнем регистре. Количество таких групп может быть от 1 до PHP_INT_MAX.

Условия поиска:

  • символ "c" может быть только в начале группы и в единственном числе
  • в каждой группе должна быть минимум одна цифра
  • подстрока не может заканчиваться или начинаться с символа дефиса
  • искомая подстрока может быть только последней частью пути
  • слэш (/) в конце исходной строки - не обязателен

Составил следующее регулярное выражение (?<=/)(c?\d+-?)+(?=/$|$).

<?php
$source = [
    '/path/1/',
    '/path/c1/',
    '/path/123-456/',
    '/path/c123-456/',
    '/path/123-c456/',
    '/path/c123-c456/',
    '/path/c/',
    '/path/12с3-456/',
    '/c123-456/path/',
    '/path/-123/',
    '/path/123-/',
    '/path/c123-/',
];
foreach($source as $path) {
    if(preg_match('#(?<=/)(c?\d+-?)+(?=/$|$)#', $path, $matches)) {
        echo $matches[0], ' - OK', PHP_EOL;
    } else {
        echo $path, ' - FAIL', PHP_EOL;
    }
}

Результат:

1                - OK
c1               - OK
123-456          - OK
c123-456         - OK
123-c456         - OK
c123-c456        - OK
/path/c/         - FAIL
/path/12с3-456/  - FAIL
/c123-456/path/  - FAIL
/path/-123/      - FAIL
123-             - OK // Ошибка, дефис в конце
c123-            - OK // Ошибка, дефис в конце

Практически во всех случаях отрабатывает нормально, но не могу победить случай, когда подстрока заканчивается на дефис, т.е. такого плана /123-456-/.
Собственно, с этой проблемкой связано моё обращение к сообществу и буду благодарен за подсказки в её решении.

Answer 1

Используйте

preg_match('~/\Kc?\d+(?:-c?\d+)*(?=/?$)~', $path, $matches)

См. пример работы кода на PHP и регулярного выражения.

Подробности

  • / - символ косой черты
  • \K - оператор очистки буфера текущего совпадения (тут он удаляет символ косой черты)
  • c? - один или ноль повторов (т.е. опционально) символа c
  • \d+ - одна или более цифр
  • (?:-c?\d+)* - 0 или более повторов следующей последовательности:
    • c? - один или ноль повторов символа c
    • \d+ - одна или более цифр
  • (?=/?$) - позитивный блок предварительного просмотра вперёд, требующий присутствия сразу после текущей позиции необязательного символа / и конца строки.
READ ALSO
Связь андроид с онлайн базой данных

Связь андроид с онлайн базой данных

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

66
После обновления symfony сломалась авторизация

После обновления symfony сломалась авторизация

Разрабатываю локально небольшой проект на symfonyИспользую докер

174
PHP вывод массива

PHP вывод массива

Есть массив $data = array()В него записываются данные array_push($data, data)

203
Передача информации из component в app.vue

Передача информации из component в app.vue

Подскажите , при клике по кнопке которая находится в компоненте должен меняться state в appvue

133