2010-04-16 154 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, '(.*)') 
相關問題