我的应用的用户可以通过格式字符串配置某些文件的布局。
例如,用户指定的配置值可能是:
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(),它甚至会给我一个正则表达式 - 但不会返回正确的组。
有没有一种好的方法可以做到这一点,没有像使用正则表达式安全的唯一值等替换占位符那样的黑客?
是否有某种方式(可能是第三方库?)允许以更灵活的方式剖析格式字符串,例如在占位符位置拆分字符串?
答案 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, '(.*)')