使用正则表达式作为Python的模板
我想使用正则表达式模式作为模板,不知道在Python(3或更高版本)中是否有一种方便的方法使用正则表达式作为Python的模板,python,regex,templates,Python,Regex,Templates,我想使用正则表达式模式作为模板,不知道在Python(3或更高版本)中是否有一种方便的方法 这不是正则表达式的用途,您可以使用普通的字符串格式 >>> '/something/{id}'.format(id=1) '/something/1' 将编译保存到替换之后: pattern = re.compile("/something/(?P<%s>.*)" % 1) pattern=re.compile(“/something/(?P.*)”%1) 下面是我创建的
这不是正则表达式的用途,您可以使用普通的字符串格式
>>> '/something/{id}'.format(id=1)
'/something/1'
将编译保存到替换之后:
pattern = re.compile("/something/(?P<%s>.*)" % 1)
pattern=re.compile(“/something/(?P.*)”%1)
下面是我创建的一个轻量级类,它可以满足您的需求。您可以编写一个正则表达式,并将该表达式用于匹配字符串和生成字符串
代码底部有一个关于如何使用它的小示例
通常,您可以正常构造正则表达式,并正常使用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)
重新导入
regex_type=type(重新编译(“”)
#这并不完美。如果正则表达式中有括号,它将中断。
re\u term=re.compile(r“(?[\w\d]+)\>(?P[^\)]*))
类BadFormatException(异常):
通过
类RegexTemplate(对象):
定义初始值(self,r,*args,**kwargs):
self.r=re.compile(r,*args,**kwargs)
定义报告(自我):
返回“%self.r.pattern”
def匹配(自身、*args、**kwargs):
''正则表达式匹配函数''
返回self.r.match(*args,**kwargs)
def搜索(self、*args、**kwargs):
''正则表达式匹配函数''
返回self.r.search(*args,**kwargs)
def格式(自身,**kwargs):
''以与string.Format类似的方式格式化此正则表达式。
仅支持真正的关键字替换,不支持组替换。“”
pattern=self.r.模式
def更换(m):
name=m.group('name')
reg=m.group('regex')
val=kwargs[名称]
如果未重新匹配(注册,val):
引发BadFormatException(“模板变量“%s”有一个值”
%s的,与正则表达式%s不匹配。%(名称、val、reg))
返回值
#regex子函数完成了大部分工作
值=re_term.sub(替换,模式)
#现在我们有了逃逸的特殊角色。
返回re.sub(r“\\([.\(\)\[\]])”,r“\1”,值)
def编译(*args,**kwargs):
返回RegexTemplate(*args,**kwargs)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
#构造一个典型的URL路由正则表达式
r=RegexTemplate(r“http://example\.com/(?P\d\d\d)/(?P\w+)
印刷品(r)
#这应该匹配
打印(r.match)(“http://example.com/2015/article"))
#使用URL格式生成相同的URL。
打印(r.format(year=“2015”,title=“article”))
#这不应该匹配
打印(r.match)(“http://example.com/abcd/article"))
#这将引发异常,因为年份格式不正确
尝试:
打印(r.格式(年份=“15”,标题=“文章”))
除BadFormat例外情况外,如e:
打印(e)
有一些限制:
- format函数仅适用于关键字参数(不能使用
中的\1
样式格式)string.format
- 还有一个错误是将元素与子元素匹配,例如,
。这可以通过一些工作来纠正RegexTemplate(r'(?Pbiz(baz)?))
- 如果正则表达式包含命名组之外的字符类(例如,
),我们将不知道如何格式化这些字符类[a-z123]
重新导入
从functools导入部分
unescape=partial(重新编译(r'\\(.)).sub,r'\1')
namedgroup=partial(重新编译(r'\(\?P.*?\)).sub,r'{\1}')
类别模具:
定义初始(自我,模式):
self.pattern=re.compile(模式)
self.template=unescape(namedgroup(pattern))
def格式(自身,**值):
尝试:
返回self.template.format(**值)
除KeyError外,如e:
从None引发TypeError(f'缺少参数:{e}')
def搜索(self,字符串):
尝试:
返回self.pattern.search(string.groupdict())
除属性错误外:
从“无”提升值错误(字符串)
例如,要实例化电话号码的验证程序/格式化程序,格式为(XXX)YYY-ZZZZ
:
template = r'\((?P<area>\d{3})\)\ (?P<prefix>\d{3})\-(?P<line>\d{4})'
phonenum = Mould(template)
但这是一个非常基本的框架,它忽略了许多正则表达式特性(例如,lookarounds或非捕获组)。如果需要,事情很快就会变得一团糟。在这种情况下,另一种方法是:从模板生成模式,虽然更详细,但可能更灵活,更不容易出错 下面是基本的验证器/格式化程序(
.search()
和.format()
是相同的):
导入字符串
进口稀土
FMT=string.Formatter()
类别模具:
定义初始化(自身、模板、**kwargs):
self.template=模板
self.pattern=self.make_模式(模板,**kwargs)
@静力学方法
def make_图案(模板,**kwargs):
模式=“”
#对于模板中的每个字段,添加到模式中
对于FMT.parse(模板)中的文本、字段*:
#前面转义的文本
模式+=重新转义(文本)
如果字段:
#命名的正则表达式捕获组
模式+=f'(?P{kwargs[field]})
#XXX:如果最后一个字段后面有文本,
#解析器将再迭代一次,
#因此,“如果字段”
返回重新编译(模式)
实例化:
template='({area}){prefix}-{line}'
content=dict(area=r'\d{3}',prefix=r'\d{3}',line=r'\d{4})
phonenum=Mold(模板,**内容)
执行
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)
template = r'\((?P<area>\d{3})\)\ (?P<prefix>\d{3})\-(?P<line>\d{4})'
phonenum = Mould(template)
>>> phonenum.search('(333) 444-5678')
{'area': '333', 'prefix': '444', 'line': '5678'}
>>> phonenum.format(area=111, prefix=555, line=444)
(111) 555-444