python: извлечение переменных из шаблонов строк
Я знаком с возможностью вставки переменных в строку с помощью Шаблоны, например:
Template('value is between $min and $max').substitute(min=5, max=10)
теперь я хочу знать, можно ли сделать обратное. Я хочу взять строку и извлечь из нее значения с помощью шаблона, чтобы у меня была некоторая структура данных (предпочтительно просто именованные переменные, но dict в порядке), которая содержит извлеченные значения. Например:
>>> string = 'value is between 5 and 10'
>>> d = Backwards_template('value is between $min and $max').extract(string)
>>> print d
{'min': '5', 'max':'10'}
это возможно?
4 ответов
это называется регулярные выражения:
import re
string = 'value is between 5 and 10'
m = re.match(r'value is between (.*) and (.*)', string)
print(m.group(1), m.group(2))
выход:
5 10
обновление 1. имена могут быть даны группам:
m = re.match(r'value is between (?P<min>.*) and (?P<max>.*)', string)
print(m.group('min'), m.group('max'))
но эта функция используется не часто, так как обычно достаточно проблем с более важным аспектом: как захватить именно то, что вы хотите (в этом конкретном случае это не имеет большого значения, но даже здесь: что, если строка value is between 1 and 2 and 3
-- если строка будет принята и что за min
и max
?).
обновление 2. вместо того, чтобы делать точное регулярное выражение, иногда проще комбинировать регулярные выражения и "регулярный" код следующим образом:
m = re.match(r'value is between (?P<min>.*) and (?P<max>.*)', string)
try:
value_min = float(m.group('min'))
value_max = float(m.group('max'))
except (AttributeError, ValueError): # no match or failed conversion
value_min = None
value_max = None
этот комбинированный подход особенно стоит помнить, когда ваш текст состоит из многих фрагментов (например, фраз в кавычках разных типов) для обработки: в сложных случаях сложнее определить одно регулярное выражение для обработки как разделителей, так и содержимого фрагментов чем определить несколько шагов типа text.split()
, необязательное слияние кусков и независимая обработка каждого куска (с использованием регулярных выражений и других средств).
невозможно полностью отменить замену. Проблема в том, что некоторые строки неоднозначны, например
value is between 5 and 7 and 10
будет иметь два возможных решения: min = "5", max = "7 and 10"
и min = "5 and 7", max = "10"
однако вы можете достичь полезных результатов с помощью regex:
import re
string = 'value is between 5 and 10'
template= 'value is between $min and $max'
pattern= re.escape(template)
pattern= re.sub(r'\$(\w+)', r'(?P<>.*)', pattern)
match= re.match(pattern, string)
print(match.groupdict()) # output: {'max': '10', 'min': '5'}
на behave
модуль для управляемого поведением развития предоставляет несколько различных механизмов для указания и шаблоны парсинга.
в зависимости от сложности ваших шаблонов и других потребностей вашего приложения вы можете найти тот или иной наиболее полезный. (Кроме того, вы можете украсть их предварительно написанный код.)
вы можете использовать модуль difflib для сравнения двух строк и извлечения нужной информации.
https://docs.python.org/3.6/library/difflib.html
например:
import difflib
def backwards_template(my_string, template):
my_lib = {}
entry = ''
value = ''
for s in difflib.ndiff(my_string, template):
if s[0]==' ':
if entry != '' and value != '':
my_lib[entry] = value
entry = ''
value = ''
elif s[0]=='-':
value += s[2]
elif s[0]=='+':
if s[2] != '$':
entry += s[2]
# check ending if non-empty
if entry != '' and value != '':
my_lib[entry] = value
return my_lib
my_string = 'value is between 5 and 10'
template = 'value is between $min and $max'
print(backwards_template(my_string, template))
дает: {'min': '5', 'max': '10'}