Python: Преобразуйте строку формата в регулярное выражение

Пользователи моего приложения могут настроить расположение определенных файлов через строку формата.

Например, значение конфигурации, которое указывает пользователь, могло бы быть:

layout = '%(group)s/foo-%(locale)s/file.txt'

Я теперь должен найти все такие файлы, которые уже существуют. Это кажется достаточно легким использованием модуля шарика:

glob_pattern = layout % {'group': '*', 'locale': '*'}
glob.glob(glob_pattern)

Однако теперь прибывает твердая часть: Учитывая список результатов шарика, я должен получить все те части имени файла, которые соответствовали данному заполнителю, например, все различные значения "локали".

Я думал, что генерирую регулярное выражение для строки формата, которой я мог затем соответствовать против списка результатов шарика (или затем возможно пропуск шарика и выполнение всего соответствия мне).

Но я не могу найти хороший способ создать regex и с надлежащими получениями группы и с остальной частью выхода входа.

Например, это могло бы дать мне regex, который соответствует локалям:

regex = layout % {'group': '.*', 'locale': (.*)}

Но быть уверенным regex допустим, я должен передать его через re.escape (), который затем также выходит из regex синтаксиса, который я только что вставил. Вызов re.escape () первые руины строка формата.

Я знаю, что существует fnmatch.translate (), который даже дал бы мне regex - но не тот, который возвращает надлежащие группы.

Существует ли хороший способ сделать это без взлома как замена заполнителей с regex-безопасным уникальным значением и т.д.?

Есть ли возможно некоторый путь (сторонняя библиотека, возможно?), который позволяет разделять строку формата более гибким способом, например, разделяя строку в местоположениях заполнителя?

7
задан SilentGhost 16 April 2010 в 18:06
поделиться

2 ответа

Поскольку вы используете именованные заполнители, я бы использовал именованные группы. Кажется, это работает:

import re
UNIQ='_UNIQUE_STRING_'
class MarkPlaceholders(dict):
    def __getitem__(self, key):
        return UNIQ+('(?P<%s>.*?)'%key)+UNIQ

def format_to_re(format):
    parts = (format % MarkPlaceholders()).split(UNIQ)
    for i in range(0, len(parts), 2):
        parts[i] = re.escape(parts[i])
    return ''.join(parts)

, а затем для проверки:

>>> layout = '%(group)s/foo-%(locale)s/file.txt'
>>> print format_to_re(layout)
(?P<group>.*?)\/foo\-(?P<locale>.*?)\/file\.txt
>>> pattern = re.compile(format_to_re(layout))
>>> print pattern.match('something/foo-en-gb/file.txt').groupdict()
{'locale': 'en-gb', 'group': 'something'}
2
ответ дан 7 December 2019 в 16:40
поделиться

Вы можете попробовать это; он работает вокруг ваших проблем с побегом.

unique = '_UNIQUE_STRING_'
assert unique not in layout
regexp = re.escape(layout % {'group': unique, 'locale': unique}).replace(unique, '(.*)')
1
ответ дан 7 December 2019 в 16:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: