Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I extract keywords from a Python format string?

Tags:

I want to provide automatic string formatting in an API such that:

my_api("path/to/{self.category}/{self.name}", ...) 

can be replaced with the values of attributes called out in the formatting string.


How do I extract the keyword arguments from a Python format string:

"non-keyword {keyword1} {{escaped brackets}} {} {keyword2}" => 'keyword1', 'keyword2' 
like image 890
Jace Browning Avatar asked Sep 23 '14 13:09

Jace Browning


People also ask

How do I get words out of a string in python?

Method #1 : Using split() Using the split function, we can split the string into a list of words and this is the most generic and recommended method if one wished to accomplish this particular task. But the drawback is that it fails in cases the string contains punctuation marks.


2 Answers

You can use the string.Formatter() class to parse out the fields in a string, with the Formatter.parse() method:

from string import Formatter  fieldnames = [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname] 

Demo:

>>> from string import Formatter >>> yourstring = "path/to/{self.category}/{self.name}" >>> [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname] ['self.category', 'self.name'] >>> yourstring = "non-keyword {keyword1} {{escaped brackets}} {} {keyword2}" >>> [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname] ['keyword1', 'keyword2'] 

You can parse those field names further; for that you can use the str._formatter_field_name_split() method (Python 2) / _string.formatter_field_name_split() function (Python 3) (this internal implementation detail is not otherwise exposed; Formatter.get_field() uses it internally). This function returns the first part of the name, the one that'd be looked up on in the arguments passed to str.format(), plus a generator for the rest of the field.

The generator yields (is_attribute, name) tuples; is_attribute is true if the next name is to be treated as an attribute, false if it is an item to look up with obj[name]:

try:     # Python 3     from _string import formatter_field_name_split except ImportError:     formatter_field_name_split = str._formatter_field_name_split from string import Formatter  field_references = {formatter_field_name_split(fname)[0]  for _, fname, _, _ in Formatter().parse(yourstring) if fname} 

Demo:

>>> from string import Formatter >>> from _string import formatter_field_name_split >>> yourstring = "path/to/{self.category}/{self.name}" >>> {formatter_field_name_split(fname)[0] ...  for _, fname, _, _ in Formatter().parse(yourstring) if fname} {'self'} 

Take into account that this function is part of the internal implementation details of the Formatter() class and can be changed or removed from Python without notice, and may not even be available in other Python implementations.

like image 196
Martijn Pieters Avatar answered Sep 28 '22 00:09

Martijn Pieters


Building off Martijn's answer, an easier format for the comprehensive list that I've used is:

>>> yourstring = "path/to/{self.category}/{self.name}" >>> [x[1] for x in yourstring._formatter_parser() if x[1]] ['self.category', 'self.name'] 

It's functionally exactly the same, just much easier to digest.

like image 20
MacMcIrish Avatar answered Sep 27 '22 23:09

MacMcIrish