#php #regex #preg-match
Вопрос:
В нашей базе данных хранятся тысячи структурированных имен файлов, и, к сожалению, многие сотни были вручную изменены на имена, которые не соответствуют нашему соглашению об именовании. Используя регулярное выражение, я пытаюсь сопоставить правильные имена файлов, чтобы идентифицировать все неправильно названные. Все файлы относятся к повестке дня собрания, и в названии используются дата, тип собрания, номер пункта повестки дня и описание.
Наше соглашение об именовании заключается yyyymmdd_aa[_bbb]_ccccc.pdf
в том, где:
- yyyymmdd-это дата (и при необходимости может использовать символы подчеркивания, такие как yyyy_mm_dd)
- aa-это код типа собрания из 2-3 символов
- bbb является необязательным пунктом повестки дня
- ccccc-это описание файла произвольной формы переменной длины (только буквенно-цифровое).
Примеры имен файлов:
20200225_RM_agenda.pdf
20200225_RM_2_memo.pdf
20200225_SS1_3c_presenTATION.pdf
20200225_CA_4d_SiGnEd.pdf
20200225_RM_5_Order1234.pdf
2021_02_25_EV_Notice.pdf
Регулярное выражение, которое я использую для сопоставления этих файлов, приведено ниже (демонстрация регулярного выражения).:
/^(d{4}[_]?d{2}[_]?d{2})_(w{2,3})_([a-z0-9]{1,3})_?(. )?.pdf/i
Проблема: В целом, это работает нормально, НО если номер повестки дня («bbb») ОТСУТСТВУЕТ в имени файла, регулярное выражение захватывает и возвращает первые 3 символа описания. Мне кажется, что 3-я группа захвата _([a-z0-9]{1,3})_
говорит 1-3 буквенно-цифровых символа между подчеркиваниями, но я не знаю, как «принудительно использовать разделители подчеркивания» или иным образом сообщить ей, что группы может не быть, и что теперь она просматривает описательный текст. Это можно увидеть в демонстрационном коде, где в первом и последнем именах файлов не используется номер повестки дня.
Мы будем признательны за любую помощь.
Ответ №1:
Необязательный идентификатор ?
предназначен для последнего, либо для символов, либо для группы. Таким образом, выражение ([a-z0-9]{1,3})_?
делает подчеркивание необязательным, но не предыдущей группой. Решение состоит в том, чтобы переместить подчеркивание в скобки.
^(d{4}[_]?d{2}[_]?d{2})_(w{2,3})_([a-z0-9]{1,3}_)?(. )?.pdf
Кроме того, [_]?
можно упростить до простого _?
, периоды имен файлов должны быть экранированы (в противном случае они являются подстановочными знаками), и мне лично нравится называть свои группы с помощью (?<name>)
синтаксиса. Собрав все это вместе, вы получите:
^(?<date>d{4}_?d{2}_?d{2})_(?<meeting_type>w{2,3})_(?<agenda>[a-z0-9]{1,3}_)?(?<description>. )?.pdf$
Демо здесь: https://regex101.com/r/BUKCih/1
Обновленный:
Я сделал некоторые обновления на основе комментариев. Я добавил $
в конец, чтобы заставить «конец имени файла», как сказал @Chris Maurer. Это не file.pdf.txt
дает мне пройти. Я также создал подгруппу и переместил имя в эту группу, что позволяет не включать завершающее подчеркивание в именованную группу. Я собираюсь оставить другой комментарий Криса об ужесточении последней соответствующей группы в покое, хотя я согласен с этим, и ОП может найти пару несоответствующих файлов, если они используют [a-z0-9]
или похожи. Я не помню сразу, поддерживает ли PHP POSIX, но если да [:alnum:]
, то его тоже можно использовать.
^(?<date>d{4}_?d{2}_?d{2})_(?<meeting_type>w{2,3})_((?<agenda>[a-z0-9]{1,3})_)?(?<description>. )?.pdf$
Обновленная демо-версия здесь: https://regex101.com/r/ebmxkF/1
Комментарии:
1. Мне это нравится. Я не знал, что вы можете так называть Группы!! Только одна вещь, в возвращенной повестке дня, это включение завершающего подчеркивания. Можно ли это опустить?
2. Еще два замечания: 1. В вашем последнем пуле указано буквенно — цифровое значение только для части ccc, но вы принимаете все символы (. ) — возможно, сделайте это . немного более строгие ограничения? 2. Вы должны добавить $ в конце после файла .pdf, чтобы не совпадать с файлом .pdfx.
3. Тх! Как Клоун регулярных выражений, я склонен уничтожать выражения, которые у меня работают, не совсем понимая, что происходит в половине случаев.
4. Я сделал некоторые обновления на основе @ChrisMaurer и заметок ОП, которые, надеюсь, помогут