代码之家  ›  专栏  ›  技术社区  ›  Paul Nathan

Python中的“就地”字符串修改

  •  19
  • Paul Nathan  · 技术社区  · 15 年前

    在Python中,字符串是不可变的。

    一个字符一个字符地浏览并修改字符串的标准习惯用法是什么?

    我能想到的唯一方法是一些与连接结果字符串相关的真正可靠的黑客。

    --

    在C中:

    for(int i = 0; i < strlen(s); i++)
    {
       s[i] = F(s[i]);
    }
    

    这是 超级的 表达能力强,能准确地说出我在做什么。这就是我要找的。

    13 回复  |  直到 15 年前
        1
  •  22
  •   bstpierre Edgar Aviles    15 年前

    不要使用字符串,使用一些可变的东西,比如bytearray:

    #!/usr/bin/python
    
    s = bytearray("my dog has fleas")
    for n in xrange(len(s)):
        s[n] = chr(s[n]).upper()
    print s
    

    结果如下:

    MY DOG HAS FLEAS
    

    编辑:

    因为这是一个 bytearray ,你(不一定)在一起工作 人物 .你在和 字节 .所以这也有效:

    s = bytearray("\x81\x82\x83")
    for n in xrange(len(s)):
        s[n] = s[n] + 1
    print repr(s)
    

    给予:

    bytearray(b'\x82\x83\x84')
    

    如果要修改Unicode字符串中的字符,可能需要使用 memoryview ,但它不直接支持Unicode。

        2
  •  5
  •   Michael Lipp    7 年前

    问题首先说明字符串是不可变的,然后询问如何在适当的位置更改它们。这有点矛盾。不管怎么说,当你搜索“python字符串就地修改”时,这个问题会出现在列表的顶部,我正在添加一个真正就地修改的答案。

    当您查看string类的方法时,字符串似乎是不可变的。但是,没有一种与C语言接口的语言能够真正提供不变的数据类型。唯一的问题是,是否必须编写C代码才能实现所需的修改。

    这里是蟒蛇 ctypes 他是你的朋友。由于它支持获取指针,并包含类似C的内存复制函数,因此python字符串 可以 按如下方式进行修改:

    s = 16 * "."
    print s
    ctypes.memmove(ctypes.c_char_p(s), "Replacement", 11)
    print s
    

    结果如下:

    ................
    Replacement.....
    

    (当然,您可以通过应用函数在运行时计算替换字符串。) F 到原始字符串的每个字符。在前面的回答中,已经展示了不同的方法。)

    请注意,我不以任何方式鼓励这样做。但是,我必须为从C++到Python映射的类编写一个替换,并包含一个方法:

    int readData(char* data, int length)
    

    (调用者应该提供具有 length 字节,然后该方法写入可用数据——最多 --返回写入的字节数。)虽然这在C/C++中是一个非常合理的API,但它不应该作为python类的方法提供,或者至少应该让API的用户知道,他们可能只将可变字节数组作为参数传递。

    正如您所料,该方法的“常用用法”如我的示例所示(创建一个字符串,并将其长度作为参数一起传递)。由于我真的不想编写一个C/C++扩展,我不得不想出一个解决方案,仅使用python在替换类中实现该行为。

        3
  •  19
  •   Ned Batchelder    15 年前

    C语言的Python模拟:

    for(int i = 0; i < strlen(s); i++)
    {
       s[i] = F(s[i]);
    }
    

    将是:

    s = "".join(F(c) for c in s)
    

    这也很有表现力。它准确地描述了正在发生的事情,但是以功能性的方式,而不是程序性的方式。

        4
  •  1
  •   Zimm3r    15 年前

    如果我需要做这样的事情,我只要把它转换成一个可变列表

    例如(尽管使用sort会更容易(见第二个示例))

    >>> s = "abcdfe"
    >>> s = list(s)
    >>> s[4] = "e"
    >>> s[5] = "f"
    >>> s = ''.join(s)
    >>> print s
    abcdef
    >>>
    # second example
    >>> s.sort()
    >>> s = ''.join(s)
    
        5
  •  11
  •   killown    15 年前

    您可以使用UserString模块:

     >>> import UserString
    ... s = UserString.MutableString('Python')
    ... print s
    Python
    >>> s[0] = 'c'
    >>> print s
    cython
    
        6
  •  3
  •   Tim McNamara    15 年前

    string.translate 可能是最接近你所追求的功能。

        7
  •  7
  •   Javier    15 年前

    我认为最具蟒蛇风格的方式是使用 map() :

    s = map(func, s) # func has been applied to every character in s
    

    这相当于写作:

    s = "".join(func(c) for c in s)
    
        8
  •  2
  •   jathanism    15 年前

    字符串是可编辑的,可以像列表一样遍历。字符串还有许多基本方法,例如 .replace() 这可能就是你想要的。所有字符串方法都返回一个新字符串。因此,您可以简单地替换其现有值,而不是就地修改字符串。

    >>> mystring = 'robot drama'
    >>> mystring = mystring.replace('r', 'g')
    >>> mystring
    'gobot dgama'
    
        9
  •  2
  •   David Z    15 年前

    将特定字符分配给字符串中的特定索引并不是一种特别常见的操作,因此如果您发现自己需要这样做,请考虑是否有更好的方法来完成该任务。但如果确实需要,最标准的方法可能是将字符串转换为列表,进行修改,然后将其转换回字符串。

    s = 'abcdefgh'
    l = list(s)
    l[3] = 'r'
    s2 = ''.join(l)
    

    编辑: 正如皮埃尔在回答中所说, bytearray 这项任务可能比 list ,只要不使用Unicode字符串。

    s = 'abcdefgh'
    b = bytearray(s)
    b[3] = 'r'
    s2 = str(b)
    
        10
  •  1
  •   Jungle Hunter    15 年前
    >>> mystring = "Th1s 1s my str1ng"
    >>> mystring.replace("1", "i")
    'This is my string'
    

    如果你想储存这个 你必须 mystring = mystring.replace("1", "i") 这是因为在Python中字符串是不可变的。

        11
  •  1
  •   John La Rooy    15 年前

    下面是一个使用translate切换“-”with”的示例大写字母“a”和“s”

    >>> from string import maketrans
    >>> trans_table = maketrans(".-a","-.A")
    >>> "foo-bar.".translate(trans_table)
    'foo.bAr-'
    

    如果只需要进行单字符替换,这比切换到字节数组并返回要高效得多

        12
  •  0
  •   Joe Koberg    15 年前
    def modifyIdx(s, idx, newchar):
        return s[:idx] + newchar + s[idx+1:]
    
        13
  •  0
  •   Odomontois    7 年前

    您可以使用 StringIO 类以接收类似文件的字符串可变接口。

        14
  •  0
  •   Saeid Amini Priyansh Sharma    6 年前

    我是这样做的:

    import tempfile
    import shutil
    
    ...
    
    f_old = open(input_file, 'r')
    with tempfile.NamedTemporaryFile() as tmp:
        for line in f_old:
            tmp.write(line.replace(old_string, new_string))
        f_old.close()
        tmp.flush()
        os.fsync(tmp)
        shutil.copy2(tmp.name, input_file)
        tmp.close()
    
        15
  •  0
  •   AbhinayBoda    3 年前

    这是我的pythonic解决方案 到位 字符串反转。

    这也解释了空白。

    笔记 :如果输入_字符串中包含任何特殊字符,则它将不匹配,下划线(“_”)除外

    i/p- “你好,世界” =>o/p- “olleH Dllow”

    import re
    
    def inplace_reversal(input_string):
        
        list_of_strings = re.findall(r'\s|(\w+)',input_string)
        
        output_string= ''
        
        for string in list_of_strings:
            
            if string == '':
                
                output_string += ' '
            
            else:
                
                output_string += string[::-1]
        
        return output_string
    
    print(inplace_reversal('__Hello__ __World__         __Hello__       __World__ '))
    
    >>> __olleH__ __dlroW__         __olleH__       __dlroW__