介绍
string 模块有一个 Template 类,它允许您使用映射对象在字符串中进行替换,例如:
>>> string.Template('var is $var').substitute({'var': 1})
'var is 1'
例如,如果尝试替换映射中缺少的元素,替换方法可能会引发 KeyError 异常
>>> string.Template('var is $var and foo is $foo').substitute({'var': 1})
KeyError: 'foo'
或者如果模板字符串无效,则可能引发 ValueError,例如它包含一个 $
字符后跟一个空格:
>>> string.Template('$ var is $var').substitute({'var': 1})
ValueError: Invalid placeholder in string: line 1, col 1
问题
给定一个模板字符串和一个映射,我想确定模板中的所有占位符是否都将被替换。为此,我会尝试进行替换并捕获任何 KeyError 异常:
def check_substitution(template, mapping):
try:
string.Template(template).substitute(mapping)
except KeyError:
return False
except ValueError:
pass
return True
但这不起作用,因为如果模板无效并引发 ValueError,则不会捕获后续的 KeyError:
>>> check_substitution('var is $var and foo is $foo', {'var': 1})
False
>>> check_substitution('$ var is $var and foo is $foo', {'var': 1})
True
但我不关心 ValueErrors。那么,解决这个问题的正确方法是什么?
最佳答案
The docs say你可以替换模式,只要它包含所有必要的命名组:
import re
from string import Template
class TemplateIgnoreInvalid(Template):
# override pattern to make sure `invalid` never matches
pattern = r"""
%(delim)s(?:
(?P<escaped>%(delim)s) | # Escape sequence of two delimiters
(?P<named>%(id)s) | # delimiter and a Python identifier
{(?P<braced>%(id)s)} | # delimiter and a braced identifier
(?P<invalid>^$) # never matches (the regex is not multilined)
)
""" % dict(delim=re.escape(Template.delimiter), id=Template.idpattern)
def check_substitution(template, **mapping):
try:
TemplateIgnoreInvalid(template).substitute(mapping)
except KeyError:
return False
else:
return True
测试
f = check_substitution
assert f('var is $var', var=1)
assert f('$ var is $var', var=1)
assert f('var is $var and foo is $foo', var=1, foo=2)
assert not f('var is $var and foo is $foo', var=1)
assert f('$ var is $var and foo is $foo', var=1, foo=2)
assert not f('$ var is $var and foo is $foo', var=1)
# support all invalid patterns
assert f('var is $var and foo is ${foo', var=1)
assert f('var is $var and foo is ${foo', var=1, foo=2) #NOTE: problematic API
assert f('var is $var and foo is ${foo and ${baz}', var=1, baz=3)
assert not f('var is $var and foo is ${foo and ${baz}', var=1)
它适用于分隔符 ($
) 的所有无效出现。
示例表明忽略无效模式会隐藏模板中的简单拼写错误,因此它不是一个好的 API。
关于python - 如何在 Python 字符串模板类上转义 $?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12768107/