从Python中获取字符串和模板中关键字的值

时间:2015-10-15 12:37:37

标签: python python-2.7

最后,我按照@jonrsharpe的例子给出了解决方案,并在此处提供。它适用于我,除了我需要使用os.path.split来拆分文件夹和文件名,以确保模板中关键字的唯一性。

def parse_kwdict(s, template, keys, kwmark='$'):
    kw2rekw = {key:'(?P<'+key+'>.*)' for key in keys}
    pattern = replace(template, kw2rekw, kwmark=kwmark)
    return re.match(pattern, s).groupdict()

def replace(template, kwdict, kwmark='$'):
    name = template
    for key, val in kwdict.iteritems():
        if val is not None:
            name = name.replace(kwmark+key, str(val))
    return name

====以下是我的问题。

我将数据存储在不同的目录树中。

可能就像

/parent/folder/$year/$day/$location/$sensor..$freq.$year.$day.dat

/parent/folder/$sensor/$year.$day/$sensor.$location.$year.$day.dat

或......

我想定义一个像

这样的函数
def parse_kwdict(s, template, keys, kwmark='$'):
    do somthing here
    return kwdict

这样我就可以从字符串和模板中提取键的值。

例如,

template = '/parent/folder/$sensor/$year.$day/$freq/$sensor.$location.$year.$day.dat'
keys = ['year', 'day', 'location', 'sensor', 'freq'] # keywords in the template
s = '/parent/folder/SensorA/2011.123/5Hz/SensorA.E.2011.123.dat'
kwdict = parse_kwdict(s, template, keys)

引起

kwdict = {'year':2011, 'day':123, 'location':'E', 'sensor':'SensorA', 'freq':'5Hz'}

我的案件要处理的一些注意事项,

  1. 关键字的值中有无空格

  2. 模板中的关键字之间总是有字母,点,下划线,斜线等分隔符。

  3. 模板中的关键字列在keys(keyword ='$'+ key)中,它们完全不同。 $freq$frequency这样的关键字不会产生默默无闻。

  4. 关键字仅包含字母,不包含特殊字符。

  5. 关键字的值包括字母和数字,没有特殊字符,但也可以是''。

  6. 关键字可以在模板和字符串中出现一次或多次,也可以不存在。如果关键字出现多次,则字符串中的值相同。

2 个答案:

答案 0 :(得分:1)

以下是您可以采取的方法的一般示例;满足您的需求所需的适应性对我来说并不完全清楚。基本上它是从基于$的模板字符串转换为具有命名捕获组的正则表达式模式,然后使用它从实际路径中提取数据:

>>> import re

>>> template = '/parent/folder/$freq/$name.dat'  # base template
>>> parts = {
    'freq': r'(?P<freq>\d+Hz)',  # one or more digits then Hz
    'name': r'(?P<name>[a-z]{3,8})',  # three to eight lowercase letters
}  # patterns for the parts of the template

>>> pattern = re.sub(
    r'\$([^/.]+)',  # dollar followed by characters excluding / and .
    lambda match: parts[match.group(1)], 
    template
)  # re.sub creates the pattern to match the actual path
>>> pattern
'/parent/folder/(?P<freq>\\d+Hz)/(?P<name>[a-z]{3,8}).dat'

>>> re.match(
    pattern,     
    '/parent/folder/5Hz/hello.dat'
).groupdict()  # re.match extracts the appropriate data
{'freq': '5Hz', 'name': 'hello'}

请注意,字典键必须是唯一的,因此,例如$year在您的模板中出现两次,您必须想出一些方法来区分这两个值。

答案 1 :(得分:0)

短篇小说:你不能(在一般情况下)可靠地逆转合并,你的第一个例子是明确的:template = 'T$a$b_an_$c' string = 'This is_an_example'可以给a='' b='his is'a='h' b='is is',{ {1}}等等。

长篇故事:

  • 首先需要解析模板以识别固定部分和可替换标记:可替换标记为a='hi' b='s is'后跟$范围内的单个小写字符,修复了所有剩余的标记
  • 然后你需要在固定的部分中逃避所有特殊字符(至少a-z或许其他人)
  • 然后通过.?(){}\:替换模板中的可替换标记来构建正则表达式,并使用其转义值替换固定部分
  • 如果匹配可能,
  • 将字符串与正则表达式匹配应该给出一个可能的映射(可能还有其他映射)。 小心:可能还有其他可能性

您可以尝试使用 ungreedy 匹配(.*代替.*?)。如果你得到与贪婪搜索完全相同的解决方案,解决方案应该是唯一的 - 更准确地说,我不是很确定,但是无法想象一个例子,它会是错误的

上次修改的最后评论:

  • 如果关键字不是单个字母,那么必须指明如何识别它们(这不仅仅是外壳设计师想象的.*
  • 模板${xxz}不会使用上述方法给出独特的结果:'/AAA/$a.$b.$c.txt'可以提供/AAA/x.y.z.t.txt(gready)或{ 'a' : 'x.y', 'b': 'z', 'c': 't' }(ungreedy)