Использование регулярного выражения в качестве шаблона с Python - PullRequest
6 голосов
/ 09 сентября 2010

У меня есть идея использовать шаблон регулярного выражения в качестве шаблона, и мне интересно, есть ли удобный способ сделать это в Python (3 или более поздней версии).1005 *

Ответы [ 3 ]

4 голосов
/ 09 сентября 2010

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

>>> '/something/{id}'.format(id=1)
'/something/1'
1 голос
/ 17 февраля 2016

Ниже приведен легкий класс, который я создал и который делает то, что вы ищете. Вы можете написать одно регулярное выражение и использовать это выражение для и сопоставления строк и генерации строк.

В нижней части кода есть небольшой пример того, как его использовать.

Как правило, вы создаете регулярное выражение обычным образом и используете функции match и search как обычно. Функция format используется так же, как string.format, для генерации новой строки.

import re
regex_type = type(re.compile(""))

# This is not perfect. It breaks if there is a parenthesis in the regex.
re_term = re.compile(r"(?<!\\)\(\?P\<(?P<name>[\w_\d]+)\>(?P<regex>[^\)]*)\)")

class BadFormatException(Exception):
    pass

class RegexTemplate(object):
    def __init__(self, r, *args, **kwargs):
        self.r = re.compile(r, *args, **kwargs)

    def __repr__(self):
        return "<RegexTemplate '%s'>"%self.r.pattern

    def match(self, *args, **kwargs):
        '''The regex match function'''
        return self.r.match(*args, **kwargs)

    def search(self, *args, **kwargs):
        '''The regex match function'''
        return self.r.search(*args, **kwargs)

    def format(self, **kwargs):
        '''Format this regular expression in a similar way as string.format.
        Only supports true keyword replacement, not group replacement.'''
        pattern = self.r.pattern
        def replace(m):
            name = m.group('name')
            reg = m.group('regex')
            val = kwargs[name]
            if not re.match(reg, val):
                raise BadFormatException("Template variable '%s' has a value "
                    "of %s, does not match regex %s."%(name, val, reg))
            return val

        # The regex sub function does most of the work
        value = re_term.sub(replace, pattern)

        # Now we have un-escape the special characters. 
        return re.sub(r"\\([.\(\)\[\]])", r"\1", value)

def compile(*args, **kwargs):
    return RegexTemplate(*args, **kwargs)

if __name__ == '__main__':
    # Construct a typical URL routing regular expression
    r = RegexTemplate(r"http://example\.com/(?P<year>\d\d\d\d)/(?P<title>\w+)")
    print r

    # This should match
    print r.match("http://example.com/2015/article")
    # Generate the same URL using url formatting.
    print r.format(year = "2015", title = "article")

    # This should not match
    print r.match("http://example.com/abcd/article")
    # This will raise an exception because year is not formatted properly
    try:
        print r.format(year = "15", title = "article")
    except BadFormatException as e:
        print e

Существуют некоторые ограничения:

  • Функция форматирования работает только с аргументами ключевых слов (вы не можете использовать форматирование в стиле \1, как в string.format).
  • Также есть ошибка с сопоставлением элементов с подэлементами, например, RegexTemplate(r'(?P<foo>biz(baz)?)'). Это можно исправить с небольшим трудом.
  • Если ваше регулярное выражение содержит классы символов вне именованной группы (например, [a-z123]), мы не будем знать, как их отформатировать.
1 голос
/ 09 сентября 2010

Сохранить компиляцию до окончания замены:

pattern = re.compile("/something/(?P<%s>.*)" % 1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...