Bagaimana Anda mengganti kata-kata dalam daftar python?

Saya tidak berpikir bahwa memecahkan batasan ini adalah suatu kebutuhan karena ingin

text.replace(('pepper', 'red pepper', 'green pepper'), 'tomato')
3 untuk menangkap
text.replace(('pepper', 'red pepper', 'green pepper'), 'tomato')
4 terlihat seperti kasus penggunaan yang sangat jarang, di mana pengganti diambil di atas yang lain, untuk kesempatan langka ini Anda bisa menggabungkan dua penggunaan
text.replace(('pepper', 'red pepper', 'green pepper'), 'tomato')
5, juga

Bagaimana Anda mengganti kata-kata dalam daftar python?
metana

Saya pikir ada beberapa implementasi TRIE di PyPI

Saya melihat bagaimana Trie dapat memecahkan masalah ini, tetapi penggunaan memori akan menjadi masalah, dan daftar tertaut tidak dapat menggunakan caching memori berurutan (kompleksitasnya lebih rendah, tetapi runtime bisa lebih besar)
Mungkin sapuan linier yang mirip dengan penerapan penggantian saat ini adalah solusi yang lebih baik

Bagaimana Anda mengganti kata-kata dalam daftar python?
steven. daprano

Memiliki str. ganti mendukung banyak target (tetapi dengan satu
penggantian) telah disarankan berkali-kali sebelumnya, dan selalu
kandas karena masalah apa yang harus dilakukan ketika target tumpang tindih

text.replace(('pepper', 'red pepper', 'green pepper'), 'tomato')

Kesimpulannya adalah selalu merekomendasikan bahwa jika kebutuhan penggantian Anda
lebih kompleks daripada hanya mengubah satu substring pada satu waktu, Anda
harus pindah ke menggunakan ekspresi reguler

Ide yang Anda kutip sangat berbeda dengan saya, jadi jangan buru-buru menutup ini, berpikir itu adalah hal yang sama


Jika seseorang mengganti teks string, kemungkinan besar hal itu dilakukan lebih dari sekali

Mari bandingkan solusi yang tersedia

Pertimbangkan kami ingin melakukan 3 perubahan pada string

text.replace(('pepper', 'red pepper', 'green pepper'), 'tomato')
6

text: str = get_text()

changes: List[Tuple[str, str]] = [
	(a, b),
	(c, d),
	(e, f)
] # Imagine those variables are strings

Solusi umum (sama seperti yang diajarkan @luciano)

for from_, to in changes:
    text = text.replace(from_, to)
_

Solusi RegEx (disarankan oleh @steven. daprano dan berdasarkan re. sub() dokumentasi)

import re

changes: dict[str, str] = dict(changes)

def callback_repl(matchobj) -> str:
	replacement: Optional[str] = changes.get(matchobj.group(0), None)
	if replacement is not None:
		return replacement
	raise Exception('The match object don\'t match!')

re.sub(rf'({a}|{c}|{e})', callback_repl, text)

Solusi baru yang disarankan

text.replace((a, b), (c, d), (e, f))
_

Saya tidak dapat mengeluh tentang solusi pertama, ini berfungsi, satu-satunya alasan saya memposting ini adalah karena menurut saya operasi penulisan banyak penggantian sangat umum dan dapat dioptimalkan

Solusi kedua rumit untuk pekerjaan sederhana yang diselesaikannya, saya dapat melihat orang-orang menyalinnya dari StackOverflow haha, selain bercanda, pemanggilan fungsi menambahkan overhead yang tidak perlu ke algoritme

Hai, solusi lain yang mungkin dapat dilakukan adalah mengimplementasikan algoritme penggantian menggunakan metode find…

Untuk solusi saya, saya mengunduh versi txt dari "El Quijote de la mancha", agar memiliki string yang cukup panjang untuk mengukur waktu

with urlopen("https://gist.githubusercontent.com/jsdario/6d6c69398cb0c73111e49f1218960f79/raw/8d4fc4548d437e2a7203a5aeeace5477f598827d/el_quijote.txt") as f:
    text = f.read()
text = str(text, 'utf-8')
to_replace = list(set([t for t in choices(text.split(), k=4000) if len(t)>3 ]))
replace_map =  list(map(lambda x: (x, f'new_string_to_replace_with_{x}'), to_replace))
print(replace_map)
print(len(replace_map))
_

Kemudian saya membuat fungsi menggunakan panggilan bersarang untuk mengganti metode

def multireplace_v1(s, changes):
    for old, new in changes:
        s = s.replace(old, new)
    return s

Dan fungsi lain menggunakan metode find, dan membuat daftar semua kemungkinan penggantian menggunakan perubahan

def multireplace_v2(s, changes):
    right = len(s)-1
    replacements = []
    for old, new in changes:
        i = 0
        l = len(old)
        while True:
            n = text_test.find(old, i, right)
            if n == -1:
                break
            i = n + l
            replacements.append((n, i, l, new))
    replacements = sorted(replacements, key= lambda x: x[0])
    
    i = 0
    prev_s = -1
    prev_e = -1
    new_s = ""
    for b, e, l, t in replacements:
        if b >= prev_s and  b+l <= prev_e:
            continue
        prev_s = b
        prev_e = b+l
        new_s += s[i:b] + t
        i = e
    new_s += s[i:]
    return new_s

Panggilan

result1 = multireplace_v1(text, replace_map)

mengambil 3. 06 detik untuk selesai

Dan

text.replace(('pepper', 'red pepper', 'green pepper'), 'tomato')
0

mengambil 914ms

Solusi yang diusulkan lebih cepat, dan juga mencegah penggantian string yang sudah diganti, prioritasnya adalah terjadinya salah satu string dalam perubahan