2010-04-16 99 views
7

我的应用程序的用户可以通过格式字符串配置某些文件的布局。Python:将格式字符串转换为正则表达式

例如,配置值用户指定可能是:

layout = '%(group)s/foo-%(locale)s/file.txt' 

我现在需要找到一个已经存在的所有这样的文件。这似乎很容易使用水珠模块:

glob_pattern = layout % {'group': '*', 'locale': '*'} 
glob.glob(glob_pattern) 

不过,现在到了困难的部分:由于水珠结果列表中,我需要把所有这些文件名,部分匹配给定的占位符,例如所有不同的“区域设置”值。

我想我会生成格式字符串的正则表达式,然后我可以匹配全局结果列表(或可能跳过glob并完成所有匹配)。

但我找不到一个好的方式来创建正确的组捕获正则表达式,并逃脱其余的输入。

例如,这可能会给我的语言环境相匹配的正则表达式:

regex = layout % {'group': '.*', 'locale': (.*)} 

但可以肯定的正则表达式是有效的,我需要通过它通过re.escape(),然后也逃脱我刚刚插入的正则表达式语法。首先调用re.escape()会丢弃格式字符串。

我知道有fnmatch.translate(),它甚至会给我一个正则表达式 - 但不是返回正确组的那个。

有没有一种很好的方法来做到这一点,没有像正则表达式替换占位符一样安全的独特价值等黑客?

是否有可能以某种方式(第三方库或许?)允许以更灵活的方式解析格式字符串,例如在占位符位置处拆分字符串?

回答

2

由于您使用的是指定的占位符,我会使用命名组。这似乎工作:

import re 
UNIQ='_UNIQUE_STRING_' 
class MarkPlaceholders(dict): 
    def __getitem__(self, key): 
     return UNIQ+('(?P<%s>.*?)'%key)+UNIQ 

def format_to_re(format): 
    parts = (format % MarkPlaceholders()).split(UNIQ) 
    for i in range(0, len(parts), 2): 
     parts[i] = re.escape(parts[i]) 
    return ''.join(parts) 

,然后进行测试:

>>> layout = '%(group)s/foo-%(locale)s/file.txt' 
>>> print format_to_re(layout) 
(?P<group>.*?)\/foo\-(?P<locale>.*?)\/file\.txt 
>>> pattern = re.compile(format_to_re(layout)) 
>>> print pattern.match('something/foo-en-gb/file.txt').groupdict() 
{'locale': 'en-gb', 'group': 'something'} 
+0

我希望找到比使用一个唯一的标识符以外的方式,但是这是对这种做法一个有趣的自旋。特别是,我喜欢我只需要一个唯一的分隔符,而不是每个需要匹配不同正则表达式的字段。 – miracle2k 2010-04-16 20:26:22

+0

如果独特分隔符太担心你,你可以随时在其中包含一个数字并增加数字,直到你得到一些不在字符串中的东西。 – Duncan 2010-04-17 11:54:02

+0

好吧,这适用于字符串,是否有可能使这项工作更多的构造? 像解析“node%(id)03d”到“node(?P \ d \ d \ d)” – 2012-02-02 13:38:44

1

你可以试试这个;它可以解决你的问题。

unique = '_UNIQUE_STRING_' 
assert unique not in layout 
regexp = re.escape(layout % {'group': unique, 'locale': unique}).replace(unique, '(.*)') 
相关问题