2008-10-20 181 views
0

將大多數用戶習慣的簡單正則表達式格式轉換爲正確的re python正則表達式字符串的最簡單方法是什麼?字符串簡單替換

舉個例子,我需要轉換這樣的:

string = "*abc+de?" 

這樣:

string = ".*abc.+de.?" 

當然我可以通過串迴路,並建立由字符另一串字符,但是這肯定是這樣做的一種低效率的方式?

+0

您是否在談論shell globbing?如果是,那麼我認爲「?」應該轉換爲「。」。 (即單個字符) – tzot 2008-10-20 12:13:34

回答

5

那些看上去並不像你想翻譯的正則表達式,它們看起來更像是UNIX shell的水珠。 Python已經爲此做了module。它不知道你使用的「+」語法,但是我的shell也不知道,我認爲這個語法是非標準的。

>>> import fnmatch 
>>> fnmatch.fnmatch("fooabcdef", "*abcde?") 
True 
>>> help(fnmatch.fnmatch) 
Help on function fnmatch in module fnmatch: 

fnmatch(name, pat) 
    Test whether FILENAME matches PATTERN. 

    Patterns are Unix shell style: 

    *  matches everything 
    ?  matches any single character 
    [seq] matches any character in seq 
    [!seq] matches any char not in seq 

    An initial period in FILENAME is not special. 
    Both FILENAME and PATTERN are first case-normalized 
    if the operating system requires it. 
    If you don't want this, use fnmatchcase(FILENAME, PATTERN). 

>>> 
0

我會使用replace

def wildcard_to_regex(str): 
    return str.replace("*", ".*").replace("?", .?").replace("#", "\d") 

這可能不是最有效的方式,但它應該是大多數來說已經足夠高效。注意一些通配符格式允許更難處理的字符類。

0

這是做這個的Perl example。它只是簡單地使用一個表來用相應的正則表達式替換每個通配符結構。我以前自己做過這件事,但是在C中,它不應該太難以移植到Python。

1

您可能偶爾會進行這種替換,例如每次用戶輸入新的搜索字符串時,我都不會擔心解決方案的效率。

您需要生成需要從「用戶格式」轉換爲正則表達式的替換列表。爲了便於維護我將這些存儲在字典中,像@Konrad魯道夫我只想用替換法:

def wildcard_to_regex(wildcard): 
    replacements = { 
     '*': '.*', 
     '?': '.?', 
     '+': '.+', 
     } 
    regex = wildcard 
    for (wildcard_pattern, regex_pattern) in replacements.items(): 
     regex = regex.replace(wildcard_pattern, regex_pattern) 
    return regex 

請注意,這只是簡單的字符替換作品,雖然其他複雜的代碼至少可以如有必要,隱藏在wildcard_to_regex函數中。

(另外,我不知道應該?轉化爲.? - 我認爲正常的通配符有?爲「正好一個字符」,所以它的更換應該是一個簡單. - 但我下面的例子。)

2

.replacing()每個通配符都是快捷方式,但如果通配符字符串包含其他正則表達式特殊字符呢?例如。有人搜索'my.thing *'可能並不意味着''。匹配任何角色。而在最糟糕的情況下,像匹配組創建的括號可能會破壞您對正則表達式匹配的最終處理。

re.escape可用於將文字字符轉換爲正則表達式。不過你必須首先分出通配符。通常的技巧是使用re.split和一個匹配的括號,從而得到一個形式爲[literal,wildcard,literal,wildcard,literal ...]的列表。

示例代碼:

wildcards= re.compile('([?*+])') 
escapewild= {'?': '.', '*': '.*', '+': '.+'} 

def escapePart((parti, part)): 
    if parti%2==0: # even items are literals 
     return re.escape(part) 
    else: # odd items are wildcards 
     return escapewild[part] 

def convertWildcardedToRegex(s): 
    parts= map(escapePart, enumerate(wildcards.split(s))) 
    return '^%s$' % (''.join(parts))