【问题标题】:Changing one character in a string更改字符串中的一个字符
【发布时间】:2010-11-16 17:32:13
【问题描述】:

在 Python 中替换字符串中的字符最简单的方法是什么?

例如:

text = "abcdefg";
text[1] = "Z";
           ^

【问题讨论】:

    标签: python string


    【解决方案1】:

    不要修改字符串。

    将它们作为列表使用;仅在需要时将它们转换为字符串。

    >>> s = list("Hello zorld")
    >>> s
    ['H', 'e', 'l', 'l', 'o', ' ', 'z', 'o', 'r', 'l', 'd']
    >>> s[6] = 'W'
    >>> s
    ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']
    >>> "".join(s)
    'Hello World'
    

    Python 字符串是不可变的(即它们不能被修改)。有a lot 的原因。使用列表直到你别无选择,然后才将它们变成字符串。

    【讨论】:

    • 追求速度/效率的人,read this
    • "不要修改字符串。"为什么
    • "Create->modify->serialize->assign->free" 比 s[6]='W' 更有效?嗯......为什么其他语言允许它,尽管有“很多”的原因?有趣的是如何捍卫一个奇怪的设计(我想是为了爱)。为什么不建议将函数 MID(strVar,index,newChar) 添加到直接访问 char 内存位置的 Python 核心,而不是对整个字符串进行不必要的字节混洗?
    • @hacksoi,@oscar,原因很简单:在传递指针以实现修改时复制时无需引用计数,或者直接复制整个字符串以防有人想要修改该字符串- 这导致通用使用的速度增加。由于切片,不需要像 MID 这样的东西:s[:index] + c + s[index+1:]
    • 答案中的链接已失效。
    【解决方案2】:

    最快的方法?

    共有三种方式。对于寻求速度的人,我推荐“方法 2”

    方法一

    answer提供

    text = 'abcdefg'
    new = list(text)
    new[6] = 'W'
    ''.join(new)
    

    与“方法 2”相比,这相当慢

    timeit.timeit("text = 'abcdefg'; s = list(text); s[6] = 'W'; ''.join(s)", number=1000000)
    1.0411581993103027
    

    方法 2(快速方法)

    answer提供

    text = 'abcdefg'
    text = text[:1] + 'Z' + text[2:]
    

    哪个更快:

    timeit.timeit("text = 'abcdefg'; text = text[:1] + 'Z' + text[2:]", number=1000000)
    0.34651994705200195
    

    方法三:

    字节数组:

    timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)
    1.0387420654296875
    

    【讨论】:

    • 看看它对 bytearray 方法的影响也会很有趣。
    • 好建议。 bytearray 方法也比较慢:timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000) 是最快的方法的两倍。
    • 感谢测试,这让我重新思考应该如何操作 Python 字符串。
    • 不错。请编辑答案以包含方法 3(bytearray)。
    • 需要注意的是,这里大部分时间都花在了转换上……(字符串->字节数组)。如果要对字符串进行多次编辑,那么字节数组方法会更快。
    【解决方案3】:
    new = text[:1] + 'Z' + text[2:]
    

    【讨论】:

    【解决方案4】:

    Python 字符串是不可变的,您可以通过复制来更改它们。
    做你想做的最简单的方法可能是:

    text = "Z" + text[1:]
    

    text[1:] 返回 text 中从位置 1 到末尾的字符串,位置从 0 开始计数,因此“1”是第二个字符。

    编辑: 您可以对字符串的任何部分使用相同的字符串切片技术

    text = text[:1] + "Z" + text[2:]
    

    或者如果字母只出现一次,您可以使用建议的搜索和替换技术 下面

    【讨论】:

    • 我输入了第二个字符,IE。位置 1 的字符(与第一个字符,数字 0 相对)
    【解决方案5】:

    从 python 2.6 和 python 3 开始,您可以使用可变的字节数组(与字符串不同,可以按元素进行更改):

    s = "abcdefg"
    b_s = bytearray(s)
    b_s[1] = "Z"
    s = str(b_s)
    print s
    aZcdefg
    

    编辑:将 str 更改为 s

    edit2:正如 cmets 中提到的两位炼金术士,此代码不适用于 unicode。

    【讨论】:

    • 这个答案不正确。一方面,它应该是bytearray(s),而不是bytearray(str)。另一方面,这将产生:TypeError: string argument without an encoding。如果你指定一个编码,那么你会得到TypeError: an integer is required。这就是 Python 3 或 Python 2 的 unicode。如果您在 Python 2 中执行此操作(使用更正的第二行),它将不适用于非 ASCII 字符,因为它们可能不仅仅是一个字节。试试s = 'Héllo',你会得到'He\xa9llo'
    • 我在 Python 2.7.9 上再次尝试了这个。我无法重新生成您提到的错误(TypeError: string argument without an encoding)。
    • 该错误仅适用于您使用 unicode 的情况。试试s = u'abcdefg'
    • 不要这样做。此方法忽略了字符串编码的整个概念,这意味着它仅适用于 ASCII 字符。在当今时代,即使您是在说英语的国家/地区说英语,您也不能假设 ASCII。 Python3 最大的向后不兼容性,在我看来也是最重要的,是修复整个 byte = string 错误等价。不要把它带回来。
    【解决方案6】:

    这段代码不是我的。我不记得我在哪里拿的网站表格。有趣的是,您可以使用它来将一个或多个字符替换为一个或多个字符。 虽然这个回复很晚,但像我这样的新手(随时)可能会发现它很有用。

    更改文本功能。

    mytext = 'Hello Zorld'
    mytext = mytext.replace('Z', 'W')
    print mytext,
    

    【讨论】:

    • 这不能回答问题。这根本不是我们想要的。
    • 如果您想替换第一个l,则此代码不好。 mytext = mytext.replace('l', 'W') -> HeWWo Zorld
    • 如果您想通过手术仅替换 1 个字符(我就是这样),这完全符合要求。谢谢!
    • @ProfVersaggi 这绝对是错误的。请参阅上面的 Oker 的评论。
    • @Ooker 如果你想替换only第一个字符,你可以使用mytext = mytext.replace('l', 'W',1)Link to doc
    【解决方案7】:

    正如其他人所说,通常 Python 字符串应该是不可变的。

    但是,如果您使用的是 CPython,python.org 上的实现,则可以使用 ctypes 来修改内存中的字符串结构。

    这是我使用该技术清除字符串的示例。

    Mark data as sensitive in python

    为了完整起见,我提到这一点,这应该是你最后的手段,因为它是 hackish。

    【讨论】:

    • 不得已?如果你曾经这样做,你就会突然被贴上邪恶的标签!
    • @ChrisMorgan 如果你的字符串包含密码,用 s='' 清除它是不够的,因为密码仍然写在内存中的某个地方。通过 ctypes 清除它是唯一的方法。
    • @Cabu 在任何情况下我从不接受这样做的代码。如果您的数据很敏感并且您关心这样的安全性,那么 str 不适合您。 不要使用它。请改用bytearray 之类的东西。 (更好的是,将其包装在某种东西中,让您或多或少地将其视为不透明数据,以便您真正无法从中检索str,以保护您免受意外。可能成为一个图书馆。不知道。)
    【解决方案8】:

    字符串在 Python 中是不可变的,这意味着您无法更改现有字符串。 但是如果你想改变其中的任何字符,你可以创建一个新的字符串,如下所示,

    def replace(s, position, character):
        return s[:position] + character + s[position+1:]
    

    替换('King', 1, 'o')
    // 结果:Kong

    注意:如果你给的位置值大于字符串的长度,它会在末尾追加字符。

    replace('Dog', 10, 's')
    // 结果:狗

    【讨论】:

      【解决方案9】:

      实际上,使用字符串,你可以这样做:

      oldStr = 'Hello World!'    
      newStr = ''
      
      for i in oldStr:  
          if 'a' < i < 'z':    
              newStr += chr(ord(i)-32)     
          else:      
              newStr += i
      print(newStr)
      
      'HELLO WORLD!'
      

      基本上,我将“添加”+“字符串”一起“添加”到一个新字符串中:)。

      【讨论】:

      • 这会很慢,因为每个连接都必须产生一个新的字符串对象,因为它们是不可变的,这就是这个问题的意义所在。
      【解决方案10】:

      我喜欢 f-strings:

      text = f'{text[:1]}Z{text[2:]}'
      

      在我的机器中,这种方法比使用 + 连接字符串的“快速方法”快 10%:

      >>> timeit.timeit("text = 'abcdefg'; text = text[:1] + 'Z' + text[2:]", number=1000000)
      1.1691178000000093
      >>> timeit.timeit("text = 'abcdefg'; text = f'{text[:1]}Z{text[2:]}'", number =1000000)
      0.9047831999999971
      >>>
      

      【讨论】:

      • 这是一个有趣的方法。请考虑使用降价对内联代码进行格式化,并发布有关您的基准和测试的详细信息。
      【解决方案11】:

      如果你的世界是 100% ascii/utf-8(很多用例都适合那个盒子):

      b = bytearray(s, 'utf-8')
      # process - e.g., lowercasing: 
      #    b[0] = b[i+1] - 32
      s = str(b, 'utf-8')
      

      python 3.7.3

      【讨论】:

        【解决方案12】:

        我想添加另一种更改字符串中字符的方法。

        >>> text = '~~~~~~~~~~~'
        >>> text = text[:1] + (text[1:].replace(text[0], '+', 1))
        '~+~~~~~~~~~'
        

        与将字符串转换为列表并替换第 i 个值然后再次加入相比,它的速度有多快?

        列表方法

        >>> timeit.timeit("text = '~~~~~~~~~~~'; s = list(text); s[1] = '+'; ''.join(s)", number=1000000)
        0.8268570480013295
        

        我的解决方案

        >>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
        0.588400217000526
        

        【讨论】:

        • 您正在将另一个答案中的“方法 2”与“替换”答案结合起来。然后你将它与 .join 方法(不是高性能的)进行比较。总体而言,从性能或新颖性的角度来看,这似乎并没有比其他答案添加任何内容。
        【解决方案13】:

        在一行 if 语句中结合 findreplace 方法的解决方案可能是:

        ```python
        my_var = "stackoverflaw"
        my_new_var = my_var.replace('a', 'o', 1) if my_var.find('s') != -1 else my_var
        print(f"my_var = {my_var}")           # my_var = stackoverflaw
        print(f"my_new_var = {my_new_var}")   # my_new_var = stackoverflow
        ```
        

        【讨论】:

          【解决方案14】:

          试试这个:

          old_string = "mba"
          string_list = list(old_string)
          string_list[2] = "e"
          //Replace 3rd element
          
          new_string = "".join(string_list)
          
          print(new_string)
          
          

          【讨论】:

            猜你喜欢
            • 2017-06-08
            • 1970-01-01
            • 2020-03-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多