1

i need to compare a subject with a regex, and link the occurrences with a coincident key mask

key_mask = 'foo/{one}/bar/{two}/hello/{world}'

regex_mask = 'foo/(.*)/bar/(.*)/hello/(.*)'

subject = 'foo/test/bar/something/xxx'

the return should be:

{
"one": "test",
"two": "something",
"world": "xxx"
}

what is the best way to accomplish this result with the 3 inputs?

(this is for a simple url routing filtering like symfony http://symfony.com/doc/current/book/routing.html )

thanks!

4

2 回答 2

3

想到的最简单的事情是在正则表达式中使用命名组:

>>> regex_mask = 'foo/(?P<one>.*)/bar/(?P<two>.*)/hello/(?P<world>.*)'
>>> subject = 'foo/test/bar/something/hello/xxx'
>>> re.match(regex_mask, subject).groupdict()
{'world': 'xxx', 'two': 'something', 'one': 'test'}
于 2013-09-17T16:05:34.343 回答
2

最简单的方法是使用命名组,即代替普通(.*)使用(?P<name>.*),然后使用对象的groupdict()方法Match

但是,如果您无法更改问题的输入(因为您是从另一个库或任何其他原因获取它们,您可以通过key_maskusingre.sub和 using 一个简单的函数自动创建命名组正则表达式repl

import re

def to_named_group(match):
    return '(?P<{}>.*)'.format(re.escape(match.group(0)[1:-1]))

def make_regex(key_mask):
    return re.compile(re.sub(r'\{[^}]+\}', to_named_group, key_mask))

def find_matches(key_mask, text):
    return make_regex(key_mask).match(text).groupdict()

用作:

In [10]: find_matches('foo/{one}/bar/{two}/hello/{world}', 'foo/test/bar/something/hello/xxx')
Out[10]: {'one': 'test', 'two': 'something', 'world': 'xxx'}

根据您的评论更新:

很容易传递to_named_group有关要生成的正​​则表达式的更多信息。例如,您可以将代码更改为:

import re
from functools import partial

def to_named_groups(match, regexes):
    group_name = re.escape(match.group(0)[1:-1])
    group_regex = regexes.get(group_name, '.*')
    return '(?P<{}>{})'.format(group_name, group_regex)

def make_regex(key_mask, regexes):
    regex = re.sub(r'\{[^}]+\}', partial(to_named_groups, regexes=regexes),
                   key_mask)
    return re.compile(regex)

def find_matches(key_mask, text, regexes=None):
    if regexes is None:
        regexes = {}
    try:
        return make_regex(key_mask, regexes).search(text).groupdict()
    except AttributeError:
        return None

通过这种方式,您可以控制每个命名组应匹配的内容。

于 2013-09-17T16:14:31.303 回答