字符串简单替换



将大多数用户习惯的更简单的regex格式转换为正确的re-python regex字符串的最简单方法是什么?

举个例子,我需要转换这个:

string = "*abc+de?"

到此:

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

当然,我可以循环遍历字符串,并逐个字符地构建另一个字符串,但这肯定是一种效率低下的方法吗?

这些看起来不像您试图翻译的regexp,它们看起来更像unix shell globs。Python已经有了一个模块来完成这项工作。它不知道你使用的"+"语法,但我的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).
>>> 

.replacing()每个通配符都是快捷的方法,但如果通配符字符串包含其他regex特殊字符呢?例如,有人在搜索"我的东西"可能不是这个意思以匹配任何字符。在最坏的情况下,像匹配组创建括号这样的事情可能会破坏您对正则表达式匹配的最终处理。

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))

您可能只是偶尔进行这种替换,比如每次用户输入新的搜索字符串时,所以我不会担心解决方案的效率有多高。

您需要生成一个替换项列表,这些替换项需要从"用户格式"转换为正则表达式。为了便于维护,我会将这些存储在字典中,就像@Konrad Rudolph一样,我只会使用替换方法:

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函数中。

(此外,我不确定?是否应该转换为.?——我认为普通通配符的?是"恰好一个字符",所以它的替换应该是一个简单的.——但我以您的例子为例。)

我会使用replace:

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

这可能不是最有效的方法,但对于大多数目的来说,它应该足够有效。请注意,一些通配符格式允许使用更难处理的字符类。

这里有一个这样做的Perl示例。它只是简单地使用一个表将每个通配符构造替换为相应的正则表达式。我以前自己也做过,但在C中。移植到Python应该不会太难。

最新更新