14

我想获取字符串模板可能在替换中使用的所有可能关键字参数的列表。

除了重新,还有其他方法吗?

我想做这样的事情:

text="$one is a $lonely $number."
keys = get_keys(text) 
# keys = ('one', 'lonely', 'number')

我正在编写一个简单的 Mad-lib-like 程序,我想用string.formatTemplate strings执行模板替换。我想编写“故事”并让我的程序生成用户需要生成的所有“关键字”(名词、动词等)的模板文件。我知道我可以用正则表达式做到这一点,但我想知道是否有替代解决方案?我对 string.format 和 string template 的替代品持开放态度。

我认为会有解决方案,但我没有在快速搜索中遇到它。我确实找到了这个问题,使用 python 反向模板,但这并不是我真正想要的。它只是重申这可以通过re.

编辑:

我应该注意这$$是“$”的转义,而不是我想要的令牌。$$5应呈现为“$ 5”。

4

7 回答 7

31

如果可以使用,请考虑使用具有方法string.format的内置类:string.Formatterparse()

>>> from string import Formatter
>>> [i[1] for i in Formatter().parse('Hello {1} {foo}')  if i[1] is not None]
['1', 'foo']

有关更多详细信息,请参见此处

于 2012-10-23T19:12:27.463 回答
11

该类string.Template具有用作属性的模式。您可以打印模式以获取匹配组

>>> print string.Template.pattern.pattern

    \$(?:
      (?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
    )

对于你的例子,

>>> string.Template.pattern.findall("$one is a $lonely $number.")
[('', 'one', '', ''), ('', 'lonely', '', ''), ('', 'number', '', '')]

正如您在上面看到的,如果您${one}使用大括号,它将转到结果元组的第三位:

>>> string.Template.pattern.findall('${one} is a $lonely $number.')
[('', '', 'one', ''), ('', 'lonely', '', ''), ('', 'number', '', '')]

因此,如果您想获得所有密钥,则必须执行以下操作:

>>> [s[1] or s[2] for s in string.Template.pattern.findall('${one} is a $lonely $number.$$') if s[1] or s[2]]
['one', 'lonely', 'number']
于 2013-05-10T17:48:15.723 回答
4

您可以使用记录调用的检测字典或 defaultdict 将其渲染一次,然后检查它的要求。

from collections import defaultdict
d = defaultdict("bogus")
text%d
keys = d.keys()
于 2012-10-23T19:33:32.630 回答
1

str.strip()一起尝试str.split()

In [54]: import string

In [55]: text="$one is a $lonely $number."

In [56]: [x.strip(string.punctuation) for x in text.split() if x.startswith("$")]
Out[56]: ['one', 'lonely', 'number']
于 2012-10-23T19:07:08.520 回答
0

你可以试试:

def get_keys(s):
    tokens = filter(lambda x: x[0] == "$", s.split())
    return map(lambda x: x[1:], tokens)
于 2012-10-23T19:10:22.750 回答
0

为什么要避免使用正则表达式?他们为此工作得很好:

>>> re.findall(r'\$[a-z]+', "$one is a $lonely $number.")
['$one', '$lonely', '$number']

对于模板,请查看re.sub,它可以用回调调用来做几乎你想要的事情。

于 2012-10-23T19:10:55.727 回答
0
>>> import string
>>> get_keys = lambda s:[el.strip(string.punctuation) 
                         for el in s.split()if el.startswith('$')]
>>> get_keys("$one is a $lonely $number.")
['one', 'lonely', 'number']
于 2012-10-23T19:13:31.083 回答