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)
import string
import re
FMT = string.Formatter()
class Mould:
def __init__(self, template, **kwargs):
self.template = template
self.pattern = self.make_pattern(template, **kwargs)
@staticmethod
def make_pattern(template, **kwargs):
pattern = ''
# for each field in the template, add to the pattern
for text, field, *_ in FMT.parse(template):
# the escaped preceding text
pattern += re.escape(text)
if field:
# a named regex capture group
pattern += f'(?P<{field}>{kwargs[field]})'
# XXX: if there's text after the last field,
# the parser will iterate one more time,
# hence the 'if field'
return re.compile(pattern)
from string import Template
def pattern2template(regex, join_string):
tmpl_str = join_string.join(["$"+x for x in regex.groupindex.keys()])
# prepend string to match your case
tmpl_str = join_string + tmpl_str
return Template(tmpl_str)
5条答案
按热度按时间lf5gs5x21#
这不是正则表达式用途,您可以使用普通的字符串格式。
bvjveswy2#
下面是我创建的一个轻量级类,它可以做你所寻找的事情。你可以写一个正则表达式,并使用这个表达式来匹配字符串和生成字符串。
在代码的底部有一个关于如何使用它的小示例。
通常,您可以正常构造正则表达式,并正常使用
match
和search
函数。format
函数的使用与string.format
非常相似,用于生成新字符串。有一些限制:
string.format
那样使用\1
样式的格式)。RegexTemplate(r'(?P<foo>biz(baz)?)')
。这个错误可以通过一些工作来纠正。[a-z123]
),我们将不知道如何格式化它们。ogsagwnx3#
将编译保存到替换之后:
azpvetkf4#
对于非常简单的情况,最简单的方法可能是用格式字段替换指定的捕获组。
下面是一个基本的验证器/格式化器:
例如,要示例化
(XXX) YYY-ZZZZ
的电话号码的验证器/格式化器:然后:
但这是一个非常基本的框架,忽略了许多regex特性(例如,像lookarounds或非捕获组)。如果需要它们,事情会很快变得非常混乱。在这种情况下,情况正好相反:从模板生成模式虽然更冗长,但是可以更灵活并且更不容易出错。
下面是基本的验证器/格式化器(
.search()
和.format()
相同):示例化:
执行:
m528fe3b5#
如果正则表达式只是由一些预定义字符串连接起来的一组命名组,则可以将其转换为如下所示的模板字符串
在您的情况下,这给出: