使用自定义双大括号格式的Python模板安全替换

wpcxdonn  于 2022-12-10  发布在  Python
关注(0)|答案(2)|浏览(148)

我尝试用Python的模板替换{{var}}的变量。

from string import Template

class CustomTemplate(Template):
    delimiter = '{{'
    pattern = r'''
    \{\{(?:
    (?P<escaped>\{\{)|
    (?P<named>[_a-z][_a-z0-9]*)\}\}|
    (?P<braced>[_a-z][_a-z0-9]*)\}\}|
    (?P<invalid>)
    )
    '''

replacement_dict = {
    "test": "hello"
}

tpl = '''{
    "unaltered": "{{foo}}",
    "replaced": "{{test}}"
}'''

a = CustomTemplate(tpl)
b = a.safe_substitute(replacement_dict)

print(b)

输出:

{
    "unaltered": "{{foo",
    "replaced": "hello"
}

正如你所看到的,{{foo}}变量(不是替换的一部分)的右括号被剪掉了。我想这是正则表达式的编写方式(右括号\}\})?
我想用模板解决这个问题,而不是用任何其他外部库。

z9smfwbn

z9smfwbn1#

我不知道你是怎么做到的。在linux上,在python 3.4.3中(我以为我在python 2.7的某个版本中做到了),我需要把tpl变成字符串

tpl = '''
    "unaltered": "{{foo}}",
    "replaced": "{{test}}"
'''

以避免发生TypeError

>>> tpl = '''
...     "unaltered": "{{foo}}",
...     "replaced": "{{test}}"
... '''
>>> a = CustomTemplate(tpl)
>>> a.template
'\n    "unaltered": "{{foo}}",\n    "replaced": "{{test}}"\n'
>>> b = a.safe_substitute(replacement_dict)
>>> b
'\n    "unaltered": "{{foo}}",\n    "replaced": "hello"\n'

执行此操作时,{{foo}}未更改。
我尝试了上面的代码,看起来代码实际上并不适用于python 2.7.6。我将看看是否能找到一种方法使其适用于2.7.6,因为这似乎是最近linux发行版的常见版本。
更新:
http://bugs.python.org/issue1686据我所知,它在2010年应用于python 3.2,在2014年应用于python 2.7。为了使它工作,你可以应用问题1686的补丁,或者你可以用这个补丁https://hg.python.org/cpython/file/8a98ee6baa1e/Lib/string.py的实际源代码覆盖你类中的safe_substitute()。
此代码适用于2.7.6和3.4.3

from string import Template
class CustomTemplate(Template):
    delimiter = '{{'
    pattern = r'''
    \{\{(?:
    (?P<escaped>\{\{)|
    (?P<named>[_a-z][_a-z0-9]*)\}\}|
    (?P<braced>[_a-z][_a-z0-9]*)\}\}|
    (?P<invalid>)
    )
    '''

    def safe_substitute(self, *args, **kws):
        if len(args) > 1:
            raise TypeError('Too many positional arguments')
        if not args:
            mapping = kws
        elif kws:
            mapping = _multimap(kws, args[0])
        else:
            mapping = args[0]
        # Helper function for .sub()
        def convert(mo):
            named = mo.group('named') or mo.group('braced')
            if named is not None:
                try:
                    # We use this idiom instead of str() because the latter
                    # will fail if val is a Unicode containing non-ASCII
                    return '%s' % (mapping[named],)
                except KeyError:
                    return mo.group()
            if mo.group('escaped') is not None:
                return self.delimiter
            if mo.group('invalid') is not None:
                return mo.group()
            raise ValueError('Unrecognized named group in pattern',
                             self.pattern)
        return self.pattern.sub(convert, self.template)

replacement_dict = {
    "test": "hello"
}

tpl = '''{
    "escaped": "{{{{",
    "unaltered": "{{foo}}",
    "replaced": "{{test}}",
    "invalid": "{{az"
}'''

a = CustomTemplate(tpl)
b = a.safe_substitute(replacement_dict)

print (b)

结果:

Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import template
{
    "escaped": "{{",
    "unaltered": "{{foo}}",
    "replaced": "hello",
    "invalid": "{{az"
}
>>>
o2rvlv0m

o2rvlv0m2#

问题

  • 开发人员reggie希望将自定义占位符分隔符与python PEP292模板字符串一起使用。

解决方案(解决方法)

  • 开发者Reggie可以更改占位符前缀字符。
  • 该方法允许使用来自完全不同的编程语言的定界符语法。
  • 该方法实现了改变占位符语法以防止定界符冲突问题的主要目的。
  • 这种方法提供了对string.Template进行子类化的最直接的例子。

陷阱

  • 这种方法不支持双大括号占位符(如{{var}})。
  • 这种方法在开发人员不能随意改变模板语法的情况下没有帮助。

示例

import string
pass

class TemplateRubyish(string.Template):
  delimiter = '#'
  idpattern = r'[a-z][\w\,\+\=\:\-\.\x2f\x5c\*\(\)\[\]\x7c]*'

class TemplatePerlish(string.Template):
  delimiter = 'qq'
  idpattern = r'[a-z][\w\,\+\=\:\-\.\x2f\x5c\*\(\)\[\]\x7c]*'

replacement_dict = {}
replacement_dict.update({
  "age":      "34",
  "fname":    "Homer",
  "lname":    "Simpson",
});
pass

##
vout     = TemplateRubyish("""\
  Greetings #{fname} #{lname},
  You are #{age}ish years old.
""").safe_substitute(replacement_dict);
print(vout)
pass

##
vout     = TemplatePerlish("""\
  Greetings qq{fname} qq{lname},
  You are qq{age}ish years old.
""").safe_substitute(replacement_dict);
print(vout)
pass

结果

Greetings Homer Simpson,
    You are 34ish years old.

    Greetings Homer Simpson,
    You are 34ish years old.

相关问题