2008-10-20 137 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))