Как получить имена именованных переменных из строки python

Есть ли изящный способ получить имена названных %s подобных переменных строкового объекта? Как это:

 string = '%(a)s and %(b)s are friends.' names = get_names(string) # ['a', 'b'] 

Известные альтернативные способы:

  1. Имена парсеров с использованием регулярного выражения, например:

     import re names = re.findall(r'%\((\w)\)[sdf]', string) # ['a', 'b'] 
  2. Используйте .format() -собираемое форматирование и Formatter().parse(string) .

    Как получить имена переменных из строки для метода format ()

Но как насчет строки с% s-подобными переменными?

PS : python 2.7

4 Solutions collect form web for “Как получить имена именованных переменных из строки python”

Чтобы ответить на этот вопрос, вам нужно определить «изящный». Можно подумать о нескольких факторах:

  1. Является ли код коротким, легко запоминающимся, легким в написании и понятным?
  2. Повторяет ли он основную логику (т. Е. Следует принципу DRY)?
  3. Он реализует точно такую ​​же логику разбора?

К сожалению, форматирование «%» для строк реализовано в подпрограмме «PyString_Format» в файле stringojbect.c. Эта процедура не предоставляет API или перехватчики, которые разрешают доступ к анализируемой форме строки формата. Он просто создает результат, когда он анализирует строку формата. Таким образом, любое решение должно будет дублировать логику синтаксического анализа из подпрограммы C. Это означает, что DRY не соблюдается и предоставляет какое-либо решение для взлома, если вносятся изменения в спецификацию форматирования.

Алгоритм синтаксического анализа в PyString_Format включает в себя довольно сложную задачу, включая обработку вложенных скобок в именах ключей, поэтому не может быть полностью реализована с использованием регулярного выражения и не используется строка «split ()». Если не скопировать код C из PyString_Format и преобразовать его в код Python, я не вижу удаленно простого способа правильно извлекать имена ключей сопоставления при любых обстоятельствах.

Поэтому я пришел к выводу, что нет «грациозного» способа получения имен ключей сопоставления для строки формата «%» Python 2.7 "%".

Следующий код использует регулярное выражение для предоставления частичного решения, которое охватывает наиболее распространенное использование:

 import re class StringFormattingParser(object): __matcher = re.compile(r'(?<!%)%\(([^)]+)\)[-# +0-9.hlL]*[diouxXeEfFgGcrs]') @classmethod def getKeyNames(klass, formatString): return klass.__matcher.findall(formatString) # Demonstration of use with some sample format strings for value in [ '%(a)s and %(b)s are friends.', '%%(nomatch)i', '%%', 'Another %(matched)+4.5f%d%% example', '(%(should_match(but does not))s', ]: print StringFormattingParser.getKeyNames(value) # Note the following prints out "really does match"! print '%(should_match(but does not))s' % {'should_match(but does not)': 'really does match'} 

PS DRY = Не повторяйте себя ( https://en.wikipedia.org/wiki/Don%27t_repeat_yourself )

Вы также можете сделать это:

 [y[0] for y in [x.split(')') for x in s.split('%(')] if len(y)>1] 

Не знаю, квалифицируется ли это как изящное в вашей книге, но вот короткая функция, которая анализирует имена. Нет проверки ошибок, поэтому он не будет работать со строгими форматированными строками.

 def get_names(s): i = s.find('%') while 0 <= i < len(s) - 3: if s[i+1] == '(': yield(s[i+2:s.find(')', i)]) i = s.find('%', i+2) string = 'abd %(one) %%(two) 99 %%%(three)' list(get_names(string) #=> ['one', 'three'] 

Кроме того, вы можете уменьшить эту % -ную нагрузку до версии Formater .

 >>> import re >>> from string import Formatter >>> >>> string = '%(a)s and %(b)s are friends.' >>> >>> string = re.sub('((?<!%)%(\((\w)\)s))', '{\g<3>}', string) >>> >>> tuple(fn[1] for fn in Formatter().parse(string) if fn[1] is not None) ('a', 'b') >>> 

В этом случае вы можете использовать оба варианта формирования, я полагаю.

Регулярное выражение в нем зависит от того, что вы хотите.

 >>> re.sub('((?<!%)%(\((\w)\)s))', '{\g<3>}', '%(a)s and %(b)s are %(c)s friends.') '{a} and {b} are {c} friends.' >>> re.sub('((?<!%)%(\((\w)\)s))', '{\g<3>}', '%(a)s and %(b)s are %%(c)s friends.') '{a} and {b} are %%(c)s friends.' >>> re.sub('((?<!%)%(\((\w)\)s))', '{\g<3>}', '%(a)s and %(b)s are %%%(c)s friends.') '{a} and {b} are %%%(c)s friends.' 
Python - лучший язык программирования в мире.