【问题标题】:wildcard match & replace and/or multiple string wildcard matching通配符匹配和替换和/或多字符串通配符匹配
【发布时间】:2021-01-20 00:06:43
【问题描述】:

我有两个非常相关的问题:

  • 我想用通配符匹配一个字符串模式(即包含一个或多个'*'或'?') 然后用第二个通配符模式形成一个替换字符串。那里的占位符应该引用 same 匹配的子字符串 (以DOS复制命令为例)

    示例:pattern='*.txt'replacement-pattern='*.doc': 我想要aaa.txt --> aaa.docxx.txt.txt --> xx.txt.doc

    理想情况下,它可以与多个任意放置的通配符一起使用:例如,pattern='*.*'replacement-pattern='XX*.*'

    当然需要应用一些约束(例如贪婪策略)。否则,X*X*X 等模式对于字符串 XXXXXX 不是唯一的。

  • 或者,形成一个多重匹配。也就是说,我有一个或多个通配符模式,每个模式都有相同数量的通配符。每个模式都匹配一个字符串,但通配符应该引用相同的匹配文本。

    示例:pattern1='*.txt'pattern2='*-suffix.txt 应该匹配 string1='XX.txt'string2='XX-suffix.txt' 对,但不匹配 string1='XX.txt'string2='YY-suffix.txt'

    与第一个相比,这是一个定义更明确的问题,因为它避免了歧义问题,但可能非常相似。

我确信有这些任务的算法,但是,我找不到任何有用的东西。

Python 库有 fnmatch 但这不支持我想做的事情。

【问题讨论】:

    标签: python regex wildcard


    【解决方案1】:

    有很多方法可以做到这一点,但我想出了以下方法,这应该适用于您的第一个问题。根据您的示例,我假设您不想匹配空格。

    此函数将第一个传递的模式转换为正则表达式,并将传递的替换模式转换为适合re.sub 函数的字符串。

    import re
    
    def replaceWildcards(string, pattern, replacementPattern):
        splitPattern = re.split(r'([*?])', pattern)
        splitReplacement = re.split(r'([*?])', replacementPattern)
        if (len(splitPattern) != len(splitReplacement)):
            raise ValueError("Provided pattern wildcards do not match")
        reg = ""
        sub = ""
        for idx, (regexPiece, replacementPiece) in enumerate(zip(splitPattern, splitReplacement)):
            if regexPiece in ["*", "?"]:
                if replacementPiece != regexPiece:
                    raise ValueError("Provided pattern wildcards do not match")
                reg += f"(\\S{regexPiece if regexPiece == '*' else ''})" # Match anything but whitespace
                sub += f"\\{idx + 1}" # Regex matches start at 1, not 0
            else:
                reg += f"({re.escape(regexPiece)})"
                sub += f"{replacementPiece}"
        return re.sub(reg, sub, string)
    

    样本输出:

    replaceWildcards("aaa.txt xx.txt.txt aaa.bat", "*.txt", "*.doc")
    # 'aaa.doc xx.txt.doc aaa.bat'
    
    replaceWildcards("aaa10.txt a1.txt aaa23.bat", "a??.txt", "b??.doc")
    # 'aab10.doc a1.txt aaa23.bat'
    
    replaceWildcards("aaa10.txt a1-suffix.txt aaa23.bat", "a*-suffix.txt", "b*-suffix.doc")
    # 'aaa10.txt b1-suffix.doc aaa23.bat'
    
    replaceWildcards("prefix-2aaa10-suffix.txt a1-suffix.txt", "prefix-*a*-suffix.txt", "prefix-*b*-suffix.doc")
    # 'prefix-2aab10-suffix.doc a1-suffix.txt
    

    注意 f 字符串需要 Python >=3.6。

    【讨论】:

    • 太棒了。构建正则表达式并使用re.sub 的好主意。我做了一些微调(使用 . 而不是 \S 来匹配空格,仅使用 ^ 和 $ 匹配完整字符串并斜线转义替换件 sub 部分)并且效果非常好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-04
    • 1970-01-01
    • 2017-10-28
    • 2016-08-27
    • 1970-01-01
    • 2015-07-29
    相关资源
    最近更新 更多