替换字符串中多个字符的最佳方法?
- 2024-12-12 08:41:00
- admin 原创
- 76
问题描述:
我需要替换一些字符,如下所示:&
➔ &
,#
➔ #
,...
我的代码如下,但我想应该有更好的方法。有什么提示吗?
strs = strs.replace('&', '&')
strs = strs.replace('#', '#')
...
解决方案 1:
替换两个字符
我对当前答案中的所有方法以及一个额外的方法进行了计时。
输入字符串abc&def#ghi
并替换 & -> \& 和 # -> \#,最快的方法是将替换内容链接在一起,如下所示:text.replace('&', '&').replace('#', '#')
。
每个功能的时间:
a) 1000000 次循环,3 次中最佳:每次循环 1.47 μs
b) 1000000 次循环,3 次中最佳:每次循环 1.51 μs
c) 100000 次循环,3 次中最佳:每次循环 12.3 μs
d) 100000 次循环,3 次中最佳:每次循环 12 μs
e) 100000 次循环,3 次中最佳:每次循环 3.27 μs
f) 1000000 次循环,3 次中最佳:每次循环 0.817 μs
g) 100000 次循环,3 次中最佳:每次循环 3.64 μs
h) 1000000 次循环,3 次中最佳:每次循环 0.927 μs
i)1000000 次循环,3 次中最佳:每次循环 0.814 μs
具体功能如下:
def a(text):
chars = "&#"
for c in chars:
text = text.replace(c, "\\\" + c)
def b(text):
for ch in ['&','#']:
if ch in text:
text = text.replace(ch,"\\\"+ch)
import re
def c(text):
rx = re.compile('([&#])')
text = rx.sub(r'\\', text)
RX = re.compile('([&#])')
def d(text):
text = RX.sub(r'\\', text)
def mk_esc(esc_chars):
return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
esc = mk_esc('&#')
def e(text):
esc(text)
def f(text):
text = text.replace('&', '&').replace('#', '#')
def g(text):
replacements = {"&": "&", "#": "#"}
text = "".join([replacements.get(c, c) for c in text])
def h(text):
text = text.replace('&', r'&')
text = text.replace('#', r'#')
def i(text):
text = text.replace('&', r'&').replace('#', r'#')
时间安排如下:
python -mtimeit -s"import time_functions" "time_functions.a('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.b('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.c('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.d('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.e('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.f('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.g('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.h('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.i('abc&def#ghi')"
替换 17 个字符
下面是执行相同操作的类似代码,但需要转义更多字符(\`*_{}>#+-.!$):
def a(text):
chars = "\\`*_{}[]()>#+-.!$"
for c in chars:
text = text.replace(c, "\\\" + c)
def b(text):
for ch in ['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:
if ch in text:
text = text.replace(ch,"\\\"+ch)
import re
def c(text):
rx = re.compile('([&#])')
text = rx.sub(r'\\', text)
RX = re.compile('([\\`*_{}[]()>#+-.!$])')
def d(text):
text = RX.sub(r'\\', text)
def mk_esc(esc_chars):
return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
esc = mk_esc('\\`*_{}[]()>#+-.!$')
def e(text):
esc(text)
def f(text):
text = text.replace('\\', '\\\\').replace('`', '`').replace('*', '*').replace('_', '_').replace('{', '{').replace('}', '}').replace('[', '[').replace(']', ']').replace('(', '(').replace(')', ')').replace('>', '>').replace('#', '#').replace('+', '+').replace('-', '-').replace('.', '.').replace('!', '!').replace('$', '$')
def g(text):
replacements = {
"\\\": "\\\\\",
"`": "`",
"*": "*",
"_": "_",
"{": "{",
"}": "}",
"[": "[",
"]": "]",
"(": "(",
")": ")",
">": ">",
"#": "#",
"+": "+",
"-": "-",
".": ".",
"!": "!",
"$": "$",
}
text = "".join([replacements.get(c, c) for c in text])
def h(text):
text = text.replace('\\', r'\\')
text = text.replace('`', r'`')
text = text.replace('*', r'*')
text = text.replace('_', r'_')
text = text.replace('{', r'{')
text = text.replace('}', r'}')
text = text.replace('[', r'[')
text = text.replace(']', r']')
text = text.replace('(', r'(')
text = text.replace(')', r')')
text = text.replace('>', r'>')
text = text.replace('#', r'#')
text = text.replace('+', r'+')
text = text.replace('-', r'-')
text = text.replace('.', r'.')
text = text.replace('!', r'!')
text = text.replace('$', r'$')
def i(text):
text = text.replace('\\', r'\\').replace('`', r'`').replace('*', r'*').replace('_', r'_').replace('{', r'{').replace('}', r'}').replace('[', r'[').replace(']', r']').replace('(', r'(').replace(')', r')').replace('>', r'>').replace('#', r'#').replace('+', r'+').replace('-', r'-').replace('.', r'.').replace('!', r'!').replace('$', r'$')
以下是相同输入字符串的结果abc&def#ghi
:
a) 100000 次循环,3 次中最佳:每次循环 6.72 μs
b) 100000 次循环,3 次中最佳:每次循环 2.64 μs
c) 100000 次循环,3 次中最佳:每次循环 11.9 μs
d) 100000 次循环,3 次中最佳:每次循环 4.92 μs
e) 100000 次循环,3 次中最佳:每次循环 2.96 μs
f) 100000 次循环,3 次中最佳:每次循环 4.29 μs
g) 100000 次循环,3 次中最佳:每次循环 4.68 μs
h) 100000 次循环,3 次中最佳:每次循环 4.73 μs
i)100000 次循环,3 次中最佳:每次循环 4.24 μs
输入更长的字符串 ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$
):
a) 100000 次循环,3 次中最佳:每次循环 7.59 μs
b) 100000 次循环,3 次中最佳:每次循环 6.54 μs
c) 100000 次循环,3 次中最佳:每次循环 16.9 μs
d) 100000 次循环,3 次中最佳:每次循环 7.29 μs
e) 100000 次循环,3 次中最佳:每次循环 12.2 μs
f) 100000 次循环,3 次中最佳:每次循环 5.38 μs
g) 10000 次循环,3 次中最佳:每次循环 21.7 μs
h) 100000 次循环,3 次中最佳:每次循环 5.7 μs
i)100000 次循环,3 次中最佳:每次循环 5.13 μs
添加几个变体:
def ab(text):
for ch in ['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:
text = text.replace(ch,"\\\"+ch)
def ba(text):
chars = "\\`*_{}[]()>#+-.!$"
for c in chars:
if c in text:
text = text.replace(c, "\\\" + c)
使用较短的输入:
ab) 100000 次循环,3 次中最佳:每次循环 7.05 μs
ba) 100000 次循环,3 次中最佳:每次循环 2.4 μs
使用较长的输入:
ab) 100000 次循环,3 次中最佳:每次循环 7.71 μs
ba) 100000 次循环,3 次中最佳:每次循环 6.08 μs
所以我将使用它ba
来提高可读性和速度。
附录
受评论中 hacks 的提示,ab
和之间的一个区别ba
是if c in text:
检查。让我们针对另外两个变体测试它们:
def ab_with_check(text):
for ch in ['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:
if ch in text:
text = text.replace(ch,"\\\"+ch)
def ba_without_check(text):
chars = "\\`*_{}[]()>#+-.!$"
for c in chars:
text = text.replace(c, "\\\" + c)
在 Python 2.7.14 和 3.6.3 上,以及在与之前设置不同的机器上,每个循环的时间以 μs 为单位,因此无法直接比较。
╭────────────╥──────┬───────────────┬──────┬──────────────────╮
│ Py, input ║ ab │ ab_with_check │ ba │ ba_without_check │
╞════════════╬══════╪═══════════════╪══════╪══════════════════╡
│ Py2, short ║ 8.81 │ 4.22 │ 3.45 │ 8.01 │
│ Py3, short ║ 5.54 │ 1.34 │ 1.46 │ 5.34 │
├────────────╫──────┼───────────────┼──────┼──────────────────┤
│ Py2, long ║ 9.3 │ 7.15 │ 6.85 │ 8.55 │
│ Py3, long ║ 7.43 │ 4.38 │ 4.41 │ 7.02 │
└────────────╨──────┴───────────────┴──────┴──────────────────┘
我们可以得出这样的结论:
持有支票的人比没有持有支票的人快 4 倍
ab_with_check
在 Python 3 上略微领先,但ba
(经检查)在 Python 2 上领先幅度更大然而,这里最大的教训是Python 3 比 Python 2 快 3 倍!Python 3 上最慢的和 Python 2 上最快的之间并没有太大的区别!
解决方案 2:
这是一个使用str.translate
and 的python3 方法str.maketrans
:
s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '&', '#': '#'})))
打印的字符串是abc&def#ghi
。
解决方案 3:
>>> string="abc&def#ghi"
>>> for ch in ['&','#']:
... if ch in string:
... string=string.replace(ch,"\\\"+ch)
...
>>> print string
abc&def#ghi
解决方案 4:
replace
只需像这样链接函数即可
strs = "abc&def#ghi"
print strs.replace('&', '&').replace('#', '#')
# abc&def#ghi
如果替换的数量较多,你可以用这种通用方法进行操作
strs, replacements = "abc&def#ghi", {"&": "&", "#": "#"}
print "".join([replacements.get(c, c) for c in strs])
# abc&def#ghi
解决方案 5:
虽然迟到了,但是我在这个问题上浪费了很多时间才找到答案。
简而言之,translate
优于replace
。如果您对功能随时间优化更感兴趣,请不要使用replace
。
translate
如果您不知道要替换的字符集是否与用于替换的字符集重叠,也可以使用。
例如:
使用时,replace
您会天真地期望代码片段"1234".replace("1", "2").replace("2", "3").replace("3", "4")
返回"2344"
,但事实上它会返回"4444"
。
翻译似乎实现了 OP 最初的愿望。
解决方案 6:
你总是要添加反斜杠吗?如果是的话,试试
import re
rx = re.compile('([&#])')
# ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)
这可能不是最有效的方法,但我认为它是最简单的。
解决方案 7:
对于 Python 3.8 及更高版本,可以使用赋值表达式
[text := text.replace(s, f"\\{s}") for s in "&#" if s in text];
虽然我不太确定这是否被视为PEP 572中描述的赋值表达式的“适当使用” ,但看起来很干净,读起来也相当好(在我看来)。如果您在 REPL 中运行此代码,末尾的分号会抑制输出。
如果您还想要所有中间字符串,这将是“合适的”。例如,(删除所有小写元音):
text = "Lorem ipsum dolor sit amet"
intermediates = [text := text.replace(i, "") for i in "aeiou" if i in text]
['Lorem ipsum dolor sit met',
'Lorm ipsum dolor sit mt',
'Lorm psum dolor st mt',
'Lrm psum dlr st mt',
'Lrm psm dlr st mt']
从好的方面来看,它确实似乎(出乎意料?)比接受的答案中的某些更快的方法更快,并且似乎在增加字符串长度和增加替换次数的情况下表现良好。
上述比较的代码如下。我使用随机字符串来简化我的生活,并且要替换的字符是从字符串本身随机选择的。(注意:我在这里使用 ipython 的 %timeit magic,因此在 ipython/jupyter 中运行它)。
import random, string
def make_txt(length):
"makes a random string of a given length"
return "".join(random.choices(string.printable, k=length))
def get_substring(s, num):
"gets a substring"
return "".join(random.choices(s, k=num))
def a(text, replace): # one of the better performing approaches from the accepted answer
for i in replace:
if i in text:
text = text.replace(i, "")
def b(text, replace):
_ = (text := text.replace(i, "") for i in replace if i in text)
def compare(strlen, replace_length):
"use ipython / jupyter for the %timeit functionality"
times_a, times_b = [], []
for i in range(*strlen):
el = make_txt(i)
et = get_substring(el, replace_length)
res_a = %timeit -n 1000 -o a(el, et) # ipython magic
el = make_txt(i)
et = get_substring(el, replace_length)
res_b = %timeit -n 1000 -o b(el, et) # ipython magic
times_a.append(res_a.average * 1e6)
times_b.append(res_b.average * 1e6)
return times_a, times_b
#----run
t2 = compare((2*2, 1000, 50), 2)
t10 = compare((2*10, 1000, 50), 10)
解决方案 8:
您可以考虑编写一个通用的转义函数:
def mk_esc(esc_chars):
return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
>>> esc = mk_esc('&#')
>>> print esc('Learn & be #1')
Learn & be #1
这样,您就可以使用需要转义的字符列表来配置您的函数。
解决方案 9:
仅供参考,这对 OP 来说没什么用,但对其他读者可能会有用(请不要投反对票,我知道这一点)。
作为一个有点荒谬但有趣的练习,我想看看我是否可以使用 python 函数式编程来替换多个字符。我很确定这不会比只调用 replace() 两次更好。如果性能是一个问题,你可以轻松地在 rust、C、julia、perl、java、javascript 甚至 awk 中解决这个问题。它使用一个名为pytoolz的外部“帮助程序”包,通过 cython 加速(cytoolz,它是一个 pypi 包)。
from cytoolz.functoolz import compose
from cytoolz.itertoolz import chain,sliding_window
from itertools import starmap,imap,ifilter
from operator import itemgetter,contains
text='&hello#hi&yo&'
char_index_iter=compose(partial(imap, itemgetter(0)), partial(ifilter, compose(partial(contains, '#&'), itemgetter(1))), enumerate)
print '\\'.join(imap(text.__getitem__, starmap(slice, sliding_window(2, chain((0,), char_index_iter(text), (len(text),))))))
我甚至不会解释这一点,因为没有人会费心使用它来完成多次替换。尽管如此,我还是觉得这样做很有成就感,并认为这可能会激励其他读者或赢得代码混淆比赛。
解决方案 10:
这个怎么样?
def replace_all(dict, str):
for key in dict:
str = str.replace(key, dict[key])
return str
然后
print(replace_all({"&":"&", "#":"#"}, "&#"))
输出
&#
类似于答案
解决方案 11:
使用 python2.7 和 python3.* 中提供的 reduce,您可以轻松地以干净且符合 Python 风格的方式替换多个子字符串。
# Lets define a helper method to make it easy to use
def replacer(text, replacements):
return reduce(
lambda text, ptuple: text.replace(ptuple[0], ptuple[1]),
replacements, text
)
if __name__ == '__main__':
uncleaned_str = "abc&def#ghi"
cleaned_str = replacer(uncleaned_str, [("&","&"),("#","#")])
print(cleaned_str) # "abc&def#ghi"
在 python2.7 中您不必导入 reduce,但在 python3.* 中您必须从 functools 模块导入它。
解决方案 12:
使用正则表达式的高级方法
import re
text = "hello ,world!"
replaces = {"hello": "hi", "world":" 2020", "!":"."}
regex = re.sub("|".join(replaces.keys()), lambda match: replaces[match.string[match.start():match.end()]], text)
print(regex)
解决方案 13:
>>> a = '&#'
>>> print a.replace('&', r'&')
&#
>>> print a.replace('#', r'#')
&#
>>>
您想要使用“原始”字符串(用替换字符串前缀“r”表示),因为原始字符串不会特殊处理反斜杠。
解决方案 14:
也许可以用一个简单的循环来替换字符:
a = '&#'
to_replace = ['&', '#']
for char in to_replace:
a = a.replace(char, "\\\"+char)
print(a)
>>> &#
解决方案 15:
这将帮助那些寻求简单解决方案的人。
def replacemany(our_str, to_be_replaced:tuple, replace_with:str):
for nextchar in to_be_replaced:
our_str = our_str.replace(nextchar, replace_with)
return our_str
os = 'the rain in spain falls mainly on the plain ttttttttt sssssssssss nnnnnnnnnn'
tbr = ('a','t','s','n')
rw = ''
print(replacemany(os,tbr,rw))
输出:
他日我 pi fll mily o 他 pli
解决方案 16:
下面给出了或条件的示例,它将从给定的字符串中删除所有 ' 和 ,。传递任意多个字符,并用 | 分隔。
import re
test = re.sub("('|,)","",str(jsonAtrList))
前:
后:
解决方案 17:
使用 .translate() 函数进行多次替换
# Original string
original_string = "12#4526&18##0"
translation_dict = {'&': r'&',
'#': r'#'}
# Create a translation table using the dictionary
translation_table = str.maketrans(translation_dict)
# Translate the string
modified_string = original_string.translate(translation_table)
print(modified_string) # Output: 12#4526&18##0
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理必备:盘点2024年13款好用的项目管理软件