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

mir*_*e2k 7 python regex formatting

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

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

layout = '%(group)s/foo-%(locale)s/file.txt'
Run Code Online (Sandbox Code Playgroud)

我现在需要找到已经存在的所有这些文件.使用glob模块这似乎很容易:

glob_pattern = layout % {'group': '*', 'locale': '*'}
glob.glob(glob_pattern)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

regex = layout % {'group': '.*', 'locale': (.*)}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Dun*_*can 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)
Run Code Online (Sandbox Code Playgroud)

然后测试:

>>> 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'}
Run Code Online (Sandbox Code Playgroud)