Get keys from the template

I would like to get a list of all possible keyword arguments that the string template can use in the wildcard.

Is there any way to do this otherwise than re?

I want to do something like this:

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

I am writing a simple Mad-lib-like program, and I want to replace the template with string.format or Template strings . I would like to write a โ€œstoryโ€, and my program will create a template file of all the โ€œkeywordsโ€ (nouns, verbs, etc.) that the user will have to create. I know I can do this with regular expressions, but I was wondering if there is an alternative solution? I am open to alternatives to the template string.format and string.

I thought it would be a solution, but I did not find it in search of a quick search. I found this question, the reverse pattern with python , but that is not quite what I am looking for. It simply confirms that this can be done with re .

EDIT:

I should notice that $$ is an escape for '$' and is not the token I want. $$5 should display the value "$ 5".

+8
python string-formatting
source share
7 answers

If you use string.format , use the built-in string.Formatter class, which has the parse() method:

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

See here for more details.

+17
source share

The string.Template class has a template that is used as an attribute. You can print the template to get the corresponding groups.

 >>> 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 ) 

And for your example

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

try str.strip() along with 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'] 
+1
source share

Why do you want to avoid regular expressions? They work well for this:

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

For templates, check re.sub , it can be called with a callback to do almost what you want.

+1
source share

You can do it once with a tool dictionary that records calls or defaultdict and then checks what it requested.

 from collections import defaultdict d = defaultdict("bogus") text%d keys = d.keys() 
+1
source share

You can try:

 def get_keys(s): tokens = filter(lambda x: x[0] == "$", s.split()) return map(lambda x: x[1:], tokens) 
0
source share
 >>> 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'] 
0
source share

All Articles