Python:将格式字符串转换为正则表达式

时间:2010-04-16 17:07:14

标签: python regex formatting

我的应用的用户可以通过格式字符串配置某些文件的布局。

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

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

我现在需要查找已经存在的所有此类文件。使用 glob 模块看起来很容易:

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

然而,现在出现了困难的部分:给定glob结果列表,我需要获得与给定占位符匹配的所有文件名部分,例如所有不同的“locale”值。

我以为我会为格式字符串生成一个正则表达式,然后我可以将其与glob结果列表匹配(或者然后可能跳过glob并自己完成所有匹配)。

但我找不到一个很好的方法来创建正则表达式,同时使用正确的组捕获,并转义其余的输入。

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

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

但是为了确保正则表达式是有效的,我需要通过re.escape()传递它,然后它也会转义我刚刚插入的正则表达式语法。调用re.escape()首先会破坏格式字符串。

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

有没有一种好的方法可以做到这一点,没有像使用正则表达式安全的唯一值等替换占位符那样的黑客?

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

2 个答案:

答案 0 :(得分: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'}

答案 1 :(得分:1)

你可以试试这个;它适用于逃避问题。

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