Thay đổi một ký tự trong chuỗi trong Python


385

Cách dễ nhất trong Python để thay thế một ký tự trong chuỗi là gì?

Ví dụ:

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

Câu trả lời:


534

Đừng sửa đổi chuỗi.

Làm việc với họ như danh sách; biến chúng thành chuỗi chỉ khi cần thiết.

>>> 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'

Chuỗi Python là bất biến (tức là chúng không thể được sửa đổi). Có rất nhiều lý do cho việc này. Sử dụng danh sách cho đến khi bạn không có lựa chọn, chỉ sau đó biến chúng thành chuỗi.


4
Những người đang tìm kiếm tốc độ / hiệu quả, hãy đọc nó
AneesAhmed777

4
"Đừng sửa đổi chuỗi." tại sao
hacksoi

2
"Tạo-> sửa đổi-> tuần tự hóa-> gán-> miễn phí" hiệu quả hơn s [6] = 'W'? Hmm ... Tại sao các ngôn ngữ khác cho phép nó, bất chấp "rất nhiều" lý do đó? Thật thú vị khi một thiết kế kỳ lạ có thể được bảo vệ (vì tình yêu tôi cho là vậy). Tại sao không đề xuất thêm một hàm MID (strVar, index, newChar) vào lõi Python để truy cập trực tiếp vào vị trí bộ nhớ char, thay vì xáo trộn byte một cách không cần thiết với toàn bộ chuỗi?
oscar

@hacksoi, @oscar, lý do khá đơn giản: không cần phải đếm lại khi chuyển con trỏ xung quanh để thực hiện sao chép khi sửa đổi hoặc sao chép toàn bộ chuỗi trong trường hợp ai đó muốn sửa đổi chuỗi đó - điều này dẫn đến tăng tốc độ chung sử dụng. Không cần những thứ như MIDdo lát:s[:index] + c + s[index+1:]
MultiSkill

1
@oscar Bằng ngôn ngữ ngu ngốc, ý tôi là họ không giao dịch với unicode trừ khi bạn nói rõ ràng với họ. Tất nhiên bạn có thể viết các ứng dụng có khả năng unicode trong C. Nhưng bạn phải quan tâm đến nó mọi lúc và cần kiểm tra nó một cách rõ ràng để tránh rắc rối. Tất cả mọi thứ là định hướng máy. Tôi đã làm việc với PHP trước khi học Python và ngôn ngữ đó là một mớ hỗn độn. Về lưu ý của bạn về CPU nhanh, tôi hoàn toàn với bạn. Nhưng một phần của vấn đề đó là sự từ chối phổ biến của tối ưu hóa sớm, dẫn đến các trình thông dịch và thư viện chậm bằng cách rò rỉ nhiều chu kỳ CPU trên đường đi.
Bachsau

202

Phương pháp nhanh nhất?

Có ba cách. Đối với những người tìm kiếm tốc độ, tôi khuyên dùng 'Phương pháp 2'

Phương pháp 1

Đưa ra bởi câu trả lời này

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

Điều này khá chậm so với 'Phương pháp 2'

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

Phương pháp 2 (PHƯƠNG PHÁP NHANH CHÓNG)

Đưa ra bởi câu trả lời này

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

Cái nào nhanh hơn nhiều:

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

Cách 3:

Mảng byte:

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

1
Sẽ rất thú vị khi xem cách nó chống lại phương thức bytearray.
gabious

1
Gợi ý tốt. Phương thức bytearray cũng chậm hơn: chậm timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)gấp đôi so với phương pháp nhanh nhất.
Mehdi Nellen

2
Đánh giá cao các bài kiểm tra, điều này khiến tôi suy nghĩ lại về cách tôi nên thao tác các chuỗi Python.
Quang phổ

1
Đẹp. Vui lòng Chỉnh sửa câu trả lời để bao gồm cả phương thức 3 (bytearray).
AneesAhmed777

1
Cần lưu ý rằng hầu hết thời gian ở đây được dành cho các chuyển đổi ... (chuỗi -> mảng byte). Nếu bạn có nhiều chỉnh sửa để thực hiện chuỗi, thì phương thức mảng byte sẽ nhanh hơn.
Ian Sudbery


37

Chuỗi Python là bất biến, bạn thay đổi chúng bằng cách tạo một bản sao.
Cách dễ nhất để làm những gì bạn muốn có lẽ là:

text = "Z" + text[1:]

Chuỗi text[1:]trả về chuỗi texttừ vị trí 1 đến cuối, vị trí được tính từ 0 nên '1' là ký tự thứ hai.

chỉnh sửa: Bạn có thể sử dụng cùng một kỹ thuật cắt chuỗi cho bất kỳ phần nào của chuỗi

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

Hoặc nếu chữ cái chỉ xuất hiện khi bạn có thể sử dụng kỹ thuật tìm kiếm và thay thế được đề xuất bên dưới


Tôi đề cập đến nhân vật thứ 2, IE. ký tự ở vị trí số 1 (như được gắn với ký tự thứ 1, số 0)
kostia

văn bản [0] + "Z" + văn bản [2:]
wbg

13

Bắt đầu với python 2.6 và python 3, bạn có thể sử dụng các phụ bản có thể thay đổi (có thể thay đổi thành phần không giống như chuỗi):

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

chỉnh sửa: Thay đổi str thành s

edit2: Như Nhà giả kim hai bit được đề cập trong các bình luận, mã này không hoạt động với unicode.


Câu trả lời này không chính xác. Đối với một điều, nó nên bytearray(s), không bytearray(str). Đối với người khác, điều này sẽ tạo ra : TypeError: string argument without an encoding. Nếu bạn chỉ định một mã hóa, sau đó bạn nhận được TypeError: an integer is required. Đó là với unicode của Python 3 hoặc Python 2. Nếu bạn làm điều này trong Python 2 (với một dòng thứ hai đã được sửa), nó sẽ không hoạt động đối với các ký tự không phải ASCII vì chúng có thể không chỉ là một byte. Hãy thử nó s = 'Héllo'và bạn sẽ nhận được 'He\xa9llo'.
Nhà giả kim hai bit

Tôi đã thử lại điều này trên Python 2.7.9. Tôi không thể tạo lại lỗi bạn đề cập (TypeError: chuỗi đối số mà không có mã hóa).
Mahmoud

Lỗi đó chỉ áp dụng nếu bạn đang sử dụng unicode. Hãy thử s = u'abcdefg'.
Nhà giả kim hai bit

4
ĐỪNG LÀM ĐIỀU NÀY. Phương thức này bỏ qua toàn bộ khái niệm mã hóa chuỗi, có nghĩa là nó chỉ xảy ra để hoạt động trên các ký tự ASCII. Trong thời đại ngày nay, bạn không thể sử dụng ASCII, ngay cả khi bạn là người nói tiếng Anh ở một quốc gia nói tiếng Anh. Không tương thích ngược lớn nhất của Python3, và theo tôi, quan trọng nhất, là sửa lỗi tương đương sai toàn bộ byte = chuỗi này. Đừng mang nó trở lại.
Adam

5

Giống như những người khác đã nói, nói chung các chuỗi Python được coi là bất biến.

Tuy nhiên, nếu bạn đang sử dụng CPython, việc triển khai tại python.org, có thể sử dụng ctypes để sửa đổi cấu trúc chuỗi trong bộ nhớ.

Dưới đây là một ví dụ nơi tôi sử dụng kỹ thuật để xóa một chuỗi.

Đánh dấu dữ liệu là nhạy cảm trong python

Tôi đề cập đến điều này vì mục đích hoàn chỉnh, và đây sẽ là giải pháp cuối cùng của bạn vì nó là hackish.


6
Phương sách cuối cùng? Nếu bạn từng làm điều này, bạn đột nhiên bị coi là ác quỷ!
Chris Morgan

@ChrisMorgan nếu chuỗi của bạn chứa mật khẩu, xóa nó bằng s = '' là không đủ vì mật khẩu vẫn được ghi ở đâu đó trong bộ nhớ. Xóa nó thông qua ctypes là cách duy nhất.
Cabu

1
@Cabu Tôi sẽ không bao giờ trong bất kỳ trường hợp nào chấp nhận mã đã làm điều đó. Nếu dữ liệu của bạn nhạy cảm và bạn quan tâm đến bảo mật như thế này, strthì đó không phải là loại phù hợp với bạn. Chỉ không sử dụng nó. Sử dụng một cái gì đó như bytearraythay thế. (Tốt hơn hết, hãy bọc nó trong một cái gì đó cho phép bạn coi nó ít nhiều là dữ liệu mờ để bạn thực sự không thể lấy dữ liệu strtừ nó, để bảo vệ bạn khỏi các tai nạn.
Chris Morgan

4

Mã này không phải của tôi. Tôi không thể nhớ lại mẫu trang web ở đâu, tôi đã lấy nó. Thật thú vị, bạn có thể sử dụng điều này để thay thế một nhân vật trở lên bằng một hoặc nhiều nhà từ thiện. Mặc dù câu trả lời này rất muộn, những người mới như tôi (bất cứ lúc nào) có thể thấy nó hữu ích.

Thay đổi chức năng Văn bản.

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

11
Điều này không trả lời câu hỏi. Đó không phải là những gì mong muốn ở tất cả.
Chris Morgan

2
Mã này là xấu nếu bạn muốn chỉ thay thế đầu tiên l. mytext = mytext.replace('l', 'W')->HeWWo Zorld
Ooker

Nếu bạn đang tìm cách phẫu thuật chỉ thay thế 1 ký tự (mà tôi là) thì điều này hoàn toàn phù hợp với dự luật. Cảm ơn!
ProfVersaggi

@ProfVersaggi Điều đó hoàn toàn sai. Xem bình luận của Ooker ở trên.
Nhà giả kim hai bit

3
@Ooker Nếu bạn muốn thay thế chỉ ký tự đầu tiên bạn có thể sử dụng mytext = mytext.replace('l', 'W',1). Liên kết đến tài liệu
Alex

2

Trên thực tế, với các chuỗi, bạn có thể làm một cái gì đó như thế này:

oldStr = 'Hello World!'    
newStr = ''

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

'HELLO WORLD!'

Về cơ bản, tôi đang "thêm" + "chuỗi" lại với nhau thành một chuỗi mới :).


4
Điều này sẽ rất chậm vì mỗi phép nối phải tạo ra một đối tượng chuỗi mới, vì chúng không thay đổi, đó là câu hỏi này là gì.
Nhà giả kim hai bit

0

nếu thế giới của bạn là 100% ascii/utf-8(rất nhiều trường hợp sử dụng phù hợp với hộp đó):

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

trăn 3.7.3


0

Tôi muốn thêm một cách khác để thay đổi một ký tự trong chuỗi.

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

Làm thế nào nhanh hơn khi so sánh với việc biến chuỗi thành danh sách và thay thế giá trị thứ i sau đó tham gia lại?.

Danh sách tiếp cận

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

Giải pháp của tôi

>>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
0.588400217000526
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.