iamjing66's Blog

https://iamjing66.github.io/

View on GitHub
17 September 2021

一个解决Python字符串中替换多个值的方法

by iamjing66

Python 中替换字符串方法


记录一次工作中的学习

背景
在某项目中需要对接收过来的字符串进行转义处理


# exp:    
# str_dict 为转义字典    
str_dict = {
    "<2c>": ",",
    "<2e>": ".",
    "<2f>": "/",
    "<2d>": "-",
    "<2b>": "+",
    "<3d>": "=",
    "<2a>": "*",
    }
# s1 为需要进行转义的字符串        

s1 = "<2d>47"

# 第一次默认认为只有一个特殊字符所以函数为       

def str_replace1(source: str):
    target = source
    for k, v in str_dict.items():
        if k in s1:
            target = source.replace(k, v)
    return target

# output: "-47"    

上面例子中没有产生问题,但是若 s1 中包含多个特殊转义字符则会出错

s1 = "<2d>46<2e>5"
# 需要的输出是 "-46.5"
# 若通过 str_replace1 函数
# output: "-46.5"

并不能输出需要的字符串

# 字典不变
str_dict = {
    "<2c>": ",",
    "<2e>": ".",
    "<2f>": "/",
    "<2d>": "-",
    "<2b>": "+",
    "<3d>": "=",
    "<2a>": "*",
    }
# s1 为多个特殊转义的字符串
s1 = "<2d>46<2e>5"

def str_replace2(source: str):
    target = source
    for k, v in str_dict.items():
        if k in s1:
            target = source.replace(k, v) # 错误行
            str_replace2(target)
    return target

# output: "-46<2e>5"

这里的输出还是错误?
因为在递归时并没有把正确的前一次结果 target 传入函数中
所以需要更改代码 target = source.replace(k, v) ==> target = target.replace(k, v)
这样更改后输出正确

output: "-46.5"

称为堆栈溢出(英语:stack overflow)wiki-维基百科-堆栈溢出
所以
我在 StackOverflow网站中提问Is there a better way to replace a string in python? -stackoverflow
获得了很多答案以及问题被判了重复扣了我2点荣誉(→_→)
个人认为很有用的一条答案是 How to replace multiple substrings of a string?

通过自定义一个 StringReplacer类实现

import re

class StringReplacer:

    def __init__(self, replacements, ignore_case=False):
        patterns = sorted(replacements, key=len, reverse=True)
        self.replacements = [replacements[k] for k in patterns]
        re_mode = re.IGNORECASE if ignore_case else 0
        self.pattern = re.compile('|'.join(("({})".format(p) for p in patterns)), re_mode)
        def tr(matcher):
            index = next((index for index,value in enumerate(matcher.groups()) if value), None)
            return self.replacements[index]
        self.tr = tr

    def __call__(self, string):
        return self.pattern.sub(self.tr, string)

table = {
    "aaa"    : "[This is three a]",
    "b+"     : "[This is one or more b]",
    r"<\w+>" : "[This is a tag]"
}

replacer = StringReplacer(table, True)

sample1 = "whatever bb, aaa, <star> BBB <end>"

print(replacer(sample1))

# output: 
# whatever [This is one or more b], [This is three a], [This is a tag] [This is one or more b] [This is a tag]

时间复杂度 (O(n)) 这样去实现将字典中键对应的值替换进字符串中,达到目的。同时很多项时时间也要比递归更快。
很棒的方法!


时间: 2021-9-17 15:17:48
作者: iamjing66
tags: python