Python中的字符串替换列表

44

有没有更短的方式来编写以下代码?

my_string = my_string.replace('A', '1')
my_string = my_string.replace('B', '2')
my_string = my_string.replace('C', '3')
my_string = my_string.replace('D', '4')
my_string = my_string.replace('E', '5')

请注意,我不需要替换那些确切的值;我只是想找到一种方法将5行以上的代码压缩至少于5行。

8个回答

73

看起来这是使用循环的好机会:

mapping = { 'A':'1', 'B':'2', 'C':'3', 'D':'4', 'E':'5'}
for k, v in mapping.iteritems():
    my_string = my_string.replace(k, v)

如果你不介意括号的话,更快的方法是:

mapping = [ ('A', '1'), ('B', '2'), ('C', '3'), ('D', '4'), ('E', '5') ]
for k, v in mapping:
    my_string = my_string.replace(k, v)

2
很奇怪,这就是我写的方式,因为问题都在于从一个字符映射到另一个字符。但实际上,你并没有将dict用作dict;你将其用作元组列表。那么,为什么不一开始就写一个元组列表呢? - John Fouhy
当然,元组列表也可以使用(并且速度更快)。我会编辑答案,包括那个选项。 - Rick Copeland
2
如果你有这个映射 {'A':'1', '1':'A'},那么结果可能不会如预期。 - Anton Krug
5
用更简洁的方式定义mapping = zip(list('ABCDE'),range(1,6)) - jrovegno
2
对于Python 3,请使用.items()而不是.iteritems() - yhd.leung
@yhd.leung - 即使如此,我在python3中仍然遇到“TypeError:需要字节状对象,而不是'str'”的问题(在2.7中完美运行)。 - Joe

49
你可以轻松地使用 string.maketrans() 创建映射字符串,并传递给 str.translate() 函数:
import string
trans = string.maketrans("ABCDE","12345")
my_string = my_string.translate(trans)

3
这很好,但在多字符模式或替换的情况下无法使用。 - Rick Copeland
正确。我从问题中推断出它是基于字符的替换。 - Matthew Schinckel
5
这其实是替换一系列字符时唯一正确的方法。比如,如果你用'<>'替换'<',再替换'>',得到的结果是'<<',但是使用翻译的方法,你会得到'><' - gaborous
2
在Python 3中,使用str.maketrans("ABCDE", "12345")函数。 - Koot6133

15

如果你想缓慢地得到错误的答案,那么在循环中使用string.replace。(虽然在没有重叠模式和替换的情况下这确实有效。)

对于可能存在重叠或较长主题字符串的一般情况,请使用re.sub:

import re

def multisub(subs, subject):
    "Simultaneously perform all substitutions on the subject string."
    pattern = '|'.join('(%s)' % re.escape(p) for p, s in subs)
    substs = [s for p, s in subs]
    replace = lambda m: substs[m.lastindex - 1]
    return re.sub(pattern, replace, subject)

>>> multisub([('hi', 'bye'), ('bye', 'hi')], 'hi and bye')
'bye and hi'

对于只包括一个字符模式和一个或零个字符替换的特殊情况,可以使用 string.maketrans。


对于使用re.sub的方法+1,因为对于重叠的匹配不清楚应该发生什么,所以对于声称string.replace给出错误答案的方法-1。因此净值为0 :) - Rick Copeland
2
str.replace 可能会给出错误的答案。对于基于字典的解决方案,请考虑字符串 "wow" 和翻译表 {'w': 'foo', 'o': 'bar'}。根据字典迭代的顺序,你可能会得到不同的结果:"fbarbarbarfbarbar" 或 "foobarfoo"。一个对于相同输入给出不同输出的函数可以说是有问题的。 - Miles
2
迈尔斯,是的,我指的就是这种问题。你也可能会遇到键本身的重叠,比如“hello”和“hell”。 - Darius Bacon

14

同时也可以查看 str.translate()。它可以根据您提供的 Unicode 字符映射表替换字符串中的字符,或者您需要指定每个字符从 chr(0) 到 chr(255) 被替换成什么。


9
替换字典 = {'A':'1','B':'2','C':'3','D':'4','E':'5'} 
对于每个键和替换项:
  将字符串中的键替换为相应的替换项。

6

我认为它可以更加高效:

mapping = { 'A':'1', 'B':'2', 'C':'3', 'D':'4', 'E':'5'}
my_string = "".join([mapping[c] if c in mapping else c for c in my_string])

我建议使用"timeit"进行一些基准测试,根据"my_string"的长度进行真实情况测试。


如果您需要同时进行多个替换,并且替换内容不仅限于单个字符,那么在我看来,这是最佳解决方案。 - Suzana
1
最终有人按照字典的意图使用它了。所有其他方法都是O(n * m),但你的方法是O(n * log(m))或更好,其中m是字典的大小。 - John Henckel

1

你可以使用Pandas在一行中完成它。

import pandas as pd

my_string="A B C test"

my_string =pd.DataFrame([my_string])[0].replace(["A","B","C","D","E"],['1','2','3','4','5'],regex=True)[0]

print(my_string)
'1 2 3 test'

0

我使用关联数组(字典)的一种方式。以下是我在使用正则表达式使文件准备好在LaTeX中部署时所使用的替换示例。

  import re
  def escapeTexString(string): # Returns TeX-friendly string
    rep = { # define desired replacements in this dictionary (mapping)
         '&': '\\&',
         '%': '\\%',
         '#': '\\#',
         '_': '\\_',
         '{': '\\{', # REGEX Special
         '}': '\\}', # REGEX Special
         '~': '\\char"007E{}', # LaTeX Special
         '$': '\\$', # REGEX Special
         '\\': '\\char"005C{}', # REGEX/LaTeX Special
         '^': '\\char"005E{}', # REGEX/LaTeX Special
         '"': '\\char"FF02{}'
        }
    # use these two lines to do the replacement (could be shortened to one line)
    pattern = re.compile("|".join(map(re.escape,rep.keys()))) # Create single pattern object (key to simultaneous replacement)
    new_string = pattern.sub(lambda match: rep[match.group(0)], string)
    return new_string

1
请在发布回答之前先阅读其他答案。您的回答与8年前Darius的回答完全相同。 - David Rios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接