使用自定义双大括号格式的 Python 模板安全替换 [英] Python template safe substitution with the custom double-braces format

查看:53
本文介绍了使用自定义双大括号格式的 Python 模板安全替换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用 Python 的模板替换 {{var}} 格式的变量.

from string 导入模板类自定义模板(模板):分隔符 = '{{'模式 = r'''\{\{(?:(?P<转义>\{\{)|(?P<命名>[_a-z][_a-z0-9]*)\}\}|(?P<支撑>[_a-z][_a-z0-9]*)\}\}|(?P<无效>))'''替换字典 = {测试":你好"}tpl = '''{未改变":{{foo}}",替换":{{test}}"}'''a = 自定义模板(tpl)b = a.safe_substitute(replacement_dict)打印(b)

输出:

<代码>{未改变":{{foo",替换":你好"}

如您所见,{{foo}} 变量(不是替换的一部分)的右括号被砍掉了.我认为这是正则表达式的编写方式(结束 \}\})?

我想用模板来解决这个问题,而不是用任何其他外部库.

解决方案

我不确定你是如何让它工作的.在 linux 上,在 python 3.4.3 中(我以为我可以使用 2.7 的某个版本)我需要使 tpl 成为一个字符串

tpl = '''"未改变": "{{foo}}",替换":{{test}}"'''

避免出现类型错误

<预><代码>>>>tpl = '''...未改变":{{foo}}",...替换":{{test}}"...'''>>>a = 自定义模板(tpl)>>>a.模板'\n "未更改": "{{foo}}",\n "replaced": "{{test}}"\n'>>>b = a.safe_substitute(replacement_dict)>>>乙'\n "未改变": "{{foo}}",\n "replaced": "hello"\n'

当我这样做时,{{foo}} 没有改变.

我尝试了上面的代码,看起来该代码实际上不适用于 python 2.7.6.我会看看我是否能找到一种方法让它在 2.7.6 上工作,因为这似乎是最近 linux 发行版的通用版本.

更新:

看起来这是 2007 年的已知错误.http://bugs.python.org/issue1686 据我所知,它在 2010 年应用于 python 3.2,在 2014 年应用于 python 2.7.就让它起作用而言,您可以应用问题 1686 的补丁,或者您可以在您的使用来自此补丁的实际源代码的类 https://hg.python.org/cpython/file/8a98ee6baa1e/Lib/string.py.

此代码适用于 2.7.6 和 3.4.3

from string 导入模板类自定义模板(模板):分隔符 = '{{'模式 = r'''\{\{(?:(?P<转义>\{\{)|(?P<命名>[_a-z][_a-z0-9]*)\}\}|(?P<支撑>[_a-z][_a-z0-9]*)\}\}|(?P<无效>))'''def safe_substitute(self, *args, **kws):如果 len(args) >1:raise TypeError('位置参数太多')如果不是参数:映射 = kws埃利夫知识分子:映射 = _multimap(kws, args[0])别的:映射 = args[0]# .sub() 的辅助函数定义转换(mo):named = mo.group('named') 或 mo.group('braced')如果命名不是无:尝试:# 我们使用这个习语而不是 str() 因为后者# 如果 val 是包含非 ASCII 的 Unicode,则会失败返回%s"%(映射[命名],)除了 KeyError:返回 mo.group()如果 mo.group('escaped') 不是 None:返回 self.delimiter如果 mo.group('invalid') 不是 None:返回 mo.group()raise ValueError('模式中无法识别的命名组',自我模式)返回 self.pattern.sub(convert, self.template)替换字典 = {测试":你好"}tpl = '''{转义":{{{{","未改变": "{{foo}}","替换": "{{test}}",无效":{{az"}'''a = 自定义模板(tpl)b = a.safe_substitute(replacement_dict)打印 (b)

结果:

Python 2.7.6(默认,2015 年 6 月 22 日,17:58:13)[GCC 4.8.2] 在 linux2 上输入帮助"、版权"、信用"或许可"以获取更多信息.>>>导入模板{转义":{{","未改变": "{{foo}}","replaced": "你好",无效":{{az"}>>>

I am trying to substitute variables in the format {{var}} with Python's Template.

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)

The output:

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

As you can see, the {{foo}} variable (which is not part of the replacement) has the closing brackets chopped off. I think it's the way the regex is written (the closing \}\})?

I want to solve this with Template, not with any other external libraries.

解决方案

I'm not sure how you got this to work. On linux, in python 3.4.3 (I thought I got this working with some version of 2.7) I needed to make tpl a string

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

to avoid getting a 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'

When I do this, {{foo}} is unaltered.

I tried the above code, and it looks like the code does not actually work with python 2.7.6. I'll see if I can find a way to make it work with 2.7.6, since that seems to be a common version with recent linux distros.

update:

Looks like this was a known bug as of 2007. http://bugs.python.org/issue1686 Far as I can tell, it was applied to python 3.2 in 2010, and python 2.7 in 2014. As far as getting this to work, you can either apply the patch for issue 1686, or you can override safe_substitute() in your class with the actual source code from this patch https://hg.python.org/cpython/file/8a98ee6baa1e/Lib/string.py.

This code works in 2.7.6, and 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)

results:

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"
}
>>> 

这篇关于使用自定义双大括号格式的 Python 模板安全替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆