Ganti case sensitif


Jawaban:


217

The stringtipe tidak mendukung ini. Anda mungkin lebih baik menggunakan sub metode ekspresi reguler dengan opsi re.IGNORECASE .

>>> import re
>>> insensitive_hippo = re.compile(re.escape('hippo'), re.IGNORECASE)
>>> insensitive_hippo.sub('giraffe', 'I want a hIPpo for my birthday')
'I want a giraffe for my birthday'

11
Jika Anda hanya melakukan penggantian tunggal, atau ingin menyimpan baris kode, lebih efisien menggunakan subtitusi tunggal dengan re.sub dan flag (? I): re.sub ('(? I)' + re .escape ('hippo'), 'jerapah', 'Saya ingin hIPpo untuk ulang tahun saya')
D Coetzee

3
Mengapa kembali hanya untuk string huruf saja? Terima kasih.
Elena

8
@ Elena, itu tidak diperlukan 'hippo', tetapi akan berguna jika nilai to-replace dimasukkan ke fungsi, jadi ini benar-benar lebih dari contoh yang baik daripada yang lainnya.
Blair Conrad

2
Selain harus berusaha keras re.escape, ada jebakan lain di sini yang gagal dihindari jawaban ini, yang dicatat di stackoverflow.com/a/15831118/1709587 : sejak re.subproses melarikan diri dari urutan, seperti dicatat dalam docs.python.org/library/re.html#re .sub , Anda harus melarikan diri semua backslash dalam string pengganti Anda atau menggunakan lambda.
Mark Amery

84
import re
pattern = re.compile("hello", re.IGNORECASE)
pattern.sub("bye", "hello HeLLo HELLO")
# 'bye bye bye'

17
Atau satu kalimat: re.sub('hello', 'bye', 'hello HeLLo HELLO', flags=re.IGNORECASE)
Louis Yang

Perhatikan bahwa re.subhanya mendukung flag ini sejak Python 2.7.
fuenfundachtzig

47

Dalam satu baris:

import re
re.sub("(?i)hello","bye", "hello HeLLo HELLO") #'bye bye bye'
re.sub("(?i)he\.llo","bye", "he.llo He.LLo HE.LLO") #'bye bye bye'

Atau, gunakan argumen "bendera" opsional:

import re
re.sub("hello", "bye", "hello HeLLo HELLO", flags=re.I) #'bye bye bye'
re.sub("he\.llo", "bye", "he.llo He.LLo HE.LLO", flags=re.I) #'bye bye bye'

14

Melanjutkan jawaban bFloch, fungsi ini tidak akan berubah satu, tetapi semua kejadian lama dengan yang baru - dalam kasus yang tidak sensitif.

def ireplace(old, new, text):
    idx = 0
    while idx < len(text):
        index_l = text.lower().find(old.lower(), idx)
        if index_l == -1:
            return text
        text = text[:index_l] + new + text[index_l + len(old):]
        idx = index_l + len(new) 
    return text

Bagus sekali. Jauh lebih baik daripada regex; ia menangani semua jenis karakter, sedangkan regex sangat cerewet tentang apa pun yang non-alfanumerik. IMHO jawaban yang dipilih.
fyngyrz

Yang harus Anda lakukan adalah keluar dari regex: jawaban yang diterima jauh lebih pendek dan lebih mudah dibaca daripada ini.
Fisikawan Gila

Escape hanya berfungsi untuk pencocokan, backslash di tujuan dapat mengacaukan semuanya.
ideasman42

4

Seperti kata Blair Conrad string.replace tidak mendukung ini.

Gunakan regex re.sub, tapi ingat untuk melarikan diri dari string pengganti terlebih dahulu. Perhatikan bahwa tidak ada opsi-flag di 2.6 untuk re.sub, jadi Anda harus menggunakan pengubah tertanam'(?i)' (atau objek-RE, lihat jawaban Blair Conrad). Juga, jebakan lain adalah bahwa sub akan memproses backslash lolos dalam teks pengganti, jika string diberikan. Untuk menghindari yang satu ini, Anda bisa memasukkan lambda.

Inilah fungsinya:

import re
def ireplace(old, repl, text):
    return re.sub('(?i)'+re.escape(old), lambda m: repl, text)

>>> ireplace('hippo?', 'giraffe!?', 'You want a hiPPO?')
'You want a giraffe!?'
>>> ireplace(r'[binfolder]', r'C:\Temp\bin', r'[BinFolder]\test.exe')
'C:\\Temp\\bin\\test.exe'

4

Fungsi ini menggunakan fungsi str.replace()dan re.findall(). Ini akan menggantikan semua kejadian patternin stringdengan replcara case-insensitive.

def replace_all(pattern, repl, string) -> str:
   occurences = re.findall(pattern, string, re.IGNORECASE)
   for occurence in occurences:
       string = string.replace(occurence, repl)
       return string

3

Ini tidak memerlukan RegularExp

def ireplace(old, new, text):
    """ 
    Replace case insensitive
    Raises ValueError if string not found
    """
    index_l = text.lower().index(old.lower())
    return text[:index_l] + new + text[index_l + len(old):] 

3
Bagus, namun ini tidak mengubah semua kejadian lama dengan yang baru, tetapi hanya kejadian pertama.
rsmoorthy

5
Itu kurang terbaca dari versi regex. Tidak perlu menemukan kembali roda di sini.
Johannes Bittner

Akan menarik untuk melakukan perbandingan kinerja antara ini dan versi yang ditingkatkan, mungkin lebih cepat, yang penting untuk beberapa aplikasi. Atau mungkin lebih lambat karena ia bekerja lebih banyak di Python ditafsirkan.
D Coetzee

2

Pengamatan menarik tentang detail dan opsi sintaks:

Python 3.7.2 (tag / v3.7.2: 9a3ffc0492, 23 Desember 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] di win32

import re
old = "TREEROOT treeroot TREerOot"
re.sub(r'(?i)treeroot', 'grassroot', old)

'akar rumput akar rumput'

re.sub(r'treeroot', 'grassroot', old)

'TREEROOT akar rumput TREerOot'

re.sub(r'treeroot', 'grassroot', old, flags=re.I)

'akar rumput akar rumput'

re.sub(r'treeroot', 'grassroot', old, re.I)

'TREEROOT akar rumput TREerOot'

Jadi awalan (? I) dalam ekspresi kecocokan atau menambahkan "flags = re.I" sebagai argumen keempat akan menghasilkan kecocokan case-insensitive. TETAPI, hanya menggunakan "re.I" sebagai argumen keempat tidak menghasilkan kecocokan case-sensitive.

Untuk perbandingan,

re.findall(r'treeroot', old, re.I)

['TREEROOT', 'treeroot', 'TREerOot']

re.findall(r'treeroot', old)

['akar pohon']


Ini tidak memberikan jawaban untuk pertanyaan itu. harap edit jawaban Anda untuk memastikan bahwa jawaban itu meningkat setelah jawaban lain yang sudah ada dalam pertanyaan ini.
hongsy

1

Saya sedang dikonversi ke urutan escape (gulir sedikit ke bawah), jadi saya mencatat bahwa re.sub mengkonversi karakter melarikan diri backslashed untuk melarikan diri dari urutan.

Untuk mencegahnya saya menulis yang berikut ini:

Ganti case sensitif.

import re
    def ireplace(findtxt, replacetxt, data):
        return replacetxt.join(  re.compile(findtxt, flags=re.I).split(data)  )

Juga, jika Anda ingin mengganti dengan karakter escape, seperti jawaban lain di sini yang mendapatkan makna khusus karakter bashslash dikonversi untuk keluar dari urutan, cukup decode pencarian Anda dan, atau ganti string. Dalam Python 3, mungkin harus melakukan sesuatu seperti .decode ("unicode_escape") # python3

findtxt = findtxt.decode('string_escape') # python2
replacetxt = replacetxt.decode('string_escape') # python2
data = ireplace(findtxt, replacetxt, data)

Diuji dalam Python 2.7.8

Semoga itu bisa membantu.


0

tidak pernah memposting jawaban sebelumnya dan utas ini benar-benar tua tetapi saya datang dengan solusi lain dan mengira saya bisa mendapatkan respons Anda, saya tidak berpengalaman dalam pemrograman Python jadi jika ada kelemahan yang muncul untuk itu, harap tunjukkan karena pembelajaran yang baik: )

i='I want a hIPpo for my birthday'
key='hippo'
swp='giraffe'

o=(i.lower().split(key))
c=0
p=0
for w in o:
    o[c]=i[p:p+len(w)]
    p=p+len(key+w)
    c+=1
print(swp.join(o))

2
Untuk belajar: umumnya ketika Anda melakukan pencarian dan mengganti sebuah string, lebih baik tidak harus mengubahnya menjadi array terlebih dahulu. Itu sebabnya jawaban pertama mungkin yang terbaik. Meskipun menggunakan modul eksternal, ia memperlakukan string sebagai satu keseluruhan string. Ini juga sedikit lebih jelas apa yang terjadi dalam proses.
isaaclw

Untuk belajar: sangat sulit bagi pengembang tanpa konteks untuk membaca kode ini dan menguraikan apa yang dilakukannya :)
Todd
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.