我需要填写一个小字符串模板。我的要求如下:
$(...)
str.format
所做的那样,例如在'hey {obj.name}'.format(obj=some_object)
我认为模块Template
中的string
类可以解决问题:它实现了第1点(占位符)和3(容错),但不幸的是它不支持"点接入"
>>> from string import Template
>>> t = Template('$(obj.get)')
>>> t.substitute(obj=dict)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Development\CDBServer_active\lib\string.py", line 172, in substitute
return self.pattern.sub(convert, self.template)
File "C:\Development\CDBServer_active\lib\string.py", line 169, in convert
self._invalid(mo)
File "C:\Development\CDBServer_active\lib\string.py", line 146, in _invalid
(lineno, colno))
ValueError: Invalid placeholder in string: line 1, col 1
如果没有第三方库或没有编写我自己的代码,有没有办法做到这一点?
答案 0 :(得分:1)
只需翻译格式字符串?
// your object
var o = {
"numbers": [
{"id":"11111"},
{"id":"22222"}
],
"letters": [
{"id":"aaaaa"},
{"id":"bbbbb"},
{"id":"33333"}
]
};
// gets the index
// a = the array to look in
// p = the property to check
// v = the value you are looking for
function getIndex(a, p, v) {
for(var i=0; i < a.length; i++) {
if(a[i][p] == v) {
return i;
}
}
}
// get the index from the letters array with property 'id' with value '33333'
var index = getIndex(o['letters'], 'id', '33333');
console.log(index);
// if you found the item
if (index !== undefined) {
// get the actual item from the array
var item = o['letters'][index];
console.log(o['letters']);
console.log(o['numbers']);
console.log(item);
// add the item to the other numbers array
o['numbers'].push(item);
// remove the item from the letters array
o['letters'].splice(index, 1);
console.log(o['letters']);
console.log(o['numbers']);
} else {
console.log('did not find the item');
}
答案 1 :(得分:1)
您可以覆盖Template
类并定义自己的模式和safe_substitute
方法以获得所需的行为:
from string import Template
class MyTemplate(Template):
pattern = r"""
\$(?:
(?P<escaped>\$)| # Escape sequence of two delimiters
(?P<named>[_a-z][_.a-z0-9]*)| # delimiter and a Python identifier
\((?P<braced>[_a-z][_.a-z0-9]*)\)| # delimiter and a braced identifier
(?P<invalid>) # Other ill-formed delimiter exprs
)
"""
def safe_substitute(*args, **kws):
if not args:
raise TypeError("descriptor 'safe_substitute' of 'Template' object "
"needs an argument")
self, args = args[0], args[1:] # allow the "self" keyword be passed
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('braced')
if named is not None:
try:
if '.' not in named:
return '%s' % (mapping[named],)
else:
attrs = named.split('.')
named, attrs = attrs[0], attrs[1:]
if not named.strip() or not all(attr.strip() for attr in attrs):
# handle cases like foo. foo.bar..spam
raise Exception()
return '%s' % reduce(lambda x, y: getattr(x, y), attrs, mapping[named])
except Exception as e:
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)
<强>演示:强>
class A(object):
def __init__(self, val):
self.val = val
def __getattr__(self, attr):
return A(self.val * 2)
def __repr__(self):
return str(self.val)
>>> t = MyTemplate('$(obj.get) $(foo) $(spam.a.b.c.d) $(A.__getattr__)')
>>> t.safe_substitute(obj=dict, foo=1, spam=A(10), A=A)
"<method 'get' of 'dict' objects> 1 160 <unbound method A.__getattr__>"
>>> t.safe_substitute(obj=A(100), foo=1, spam=A(10), A=A)
'200 1 160 <unbound method A.__getattr__>'
safe_subsitute
方法中的更改是,如果标识符中存在.
,则尝试使用reduce
getattr
计算其值:
attrs = named.split('.')
named, attrs = attrs[0], attrs[1:]
if not named.strip() or not all(attr.strip() for attr in attrs):
# handle cases like foo. foo.bar..spam
raise Exception()
return '%s' % reduce(lambda x, y: getattr(x, y), attrs, mapping[named])
请注意,如果您不希望该行为从正则表达式中删除$obj.get
组并更改函数的第一行{},则当前代码也将替换named
等命名组的值。 {1}}:
convert