python:从字符串模板中提取变量

时间:2017-03-01 16:00:16

标签: python string-formatting

我熟悉使用Templates将变量插入字符串的功能,如下所示:

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 个答案:

答案 0 :(得分:8)

这叫做regular expressions

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 - 是否应该接受字符串以及minmax是什么?)。

更新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(),可选的块合并,以及每个块的独立处理(使用正则表达式和其他方法)。

答案 1 :(得分:2)

不可能完全扭转替代。问题是某些字符串不明确,例如

value is between 5 and 7 and 10

会有两种可能的解决方案:min = "5", max = "7 and 10"min = "5 and 7", max = "10"

但是,您可以使用正则表达式获得有用的结果:

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<\1>.*)', pattern)
match= re.match(pattern, string)
print(match.groupdict()) # output: {'max': '10', 'min': '5'}

答案 2 :(得分:0)

行为驱动开发的behave module提供了一些不同的机制来指定和parsing templates.

根据模板的复杂程度以及应用的其他需求,您可能会发现其中一个或另一个最有用。 (另外,你可以窃取他们预先编写的代码。)

答案 3 :(得分:0)

您可以使用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))

给出: {&#39; min&#39;:&#39; 5&#39;,&#39; max&#39;:&#39; 10&#39;}