Sostituzione insensibile al maiuscolo / minuscolo


173

Qual è il modo più semplice per eseguire una sostituzione di stringa senza distinzione tra maiuscole e minuscole in Python?

Risposte:


217

Il stringtipo non supporta questo. Probabilmente stai meglio usando il metodo secondario dell'espressione regolare con l' opzione 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
Se stai effettuando una sola sostituzione o desideri salvare righe di codice, è più efficiente utilizzare una singola sostituzione con re.sub e il flag (? I): re.sub ('(? I)' + re .escape ('ippopotamo'), 'giraffa', 'Voglio un hIPpo per il mio compleanno')
D Coetzee,

3
Perché re.escape solo per una stringa di lettere? Grazie.
Elena,

8
@Elena, non è necessario 'hippo', ma sarebbe utile se il valore da sostituire fosse passato a una funzione, quindi è davvero più un buon esempio che altro.
Blair Conrad,

2
Oltre ad avere re.escapel'ago, c'è un'altra trappola qui che questa risposta non riesce a evitare, annotata in stackoverflow.com/a/15831118/1709587 : poiché i re.subprocessi sfuggono alle sequenze, come notato in docs.python.org/library/re.html#re .sub , devi sfuggire a tutte le barre rovesciate nella stringa di sostituzione o usare un lambda.
Mark Amery,

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

17
O one-liner: re.sub('hello', 'bye', 'hello HeLLo HELLO', flags=re.IGNORECASE)
Louis Yang

Nota che re.sub supporta questo flag solo da Python 2.7.
Fuenfundachtzig,

47

In una sola riga:

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'

In alternativa, utilizzare l'argomento facoltativo "flags":

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

Continuando sulla risposta di bFloch, questa funzione cambierà non una, ma tutte le occorrenze di vecchio con nuovo - in un modo insensibile al caso.

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

Molto ben fatto. Molto meglio di regex; gestisce tutti i tipi di personaggi, mentre il regex è molto esigente su qualsiasi cosa non alfanumerica. Risposta preferita IMHO.
fyngyrz,

Tutto quello che devi fare è sfuggire alla regex: la risposta accettata è molto più breve e più facile da leggere di così.
Fisico pazzo,

Escape funziona solo per la corrispondenza, le barre rovesciate nella destinazione possono rovinare ancora le cose.
ideasman42

4

Come dice Blair Conrad, string.replace non supporta questo.

Usa regex re.sub, ma ricorda prima di sfuggire alla stringa di sostituzione. Nota che non c'è l'opzione flags in 2.6 per re.sub, quindi dovrai usare il modificatore incorporato '(?i)'(o un oggetto RE, vedi la risposta di Blair Conrad). Inoltre, un altro inconveniente è che il sub elaborerà gli escape di barra rovesciata nel testo di sostituzione, se viene fornita una stringa. Per evitarlo si può invece passare un lambda.

Ecco una funzione:

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

Questa funzione utilizza entrambe le funzioni str.replace()e re.findall(). Sostituirà tutte le occorrenze di patternin stringcon repluna distinzione tra maiuscole e minuscole.

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

Questo non richiede 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
Buono, tuttavia questo non cambia tutte le occorrenze di vecchio con nuovo, ma solo la prima occorrenza.
rsmoorthy,

5
È meno leggibile rispetto alla versione regex. Non è necessario reinventare la ruota qui.
Johannes Bittner,

Sarebbe interessante fare un confronto delle prestazioni tra questa e le versioni potenziate, potrebbe essere più veloce, il che conta per alcune applicazioni. Oppure potrebbe essere più lento perché funziona di più in Python interpretato.
D Coetzee,

2

Un'osservazione interessante sui dettagli e le opzioni della sintassi:

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

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

'grassroot grassroot grassroot'

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

"TREEROOT grassroot TREerOot"

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

'grassroot grassroot grassroot'

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

"TREEROOT grassroot TREerOot"

Quindi il prefisso (? I) nell'espressione di corrispondenza o l'aggiunta di "flags = re.I" come quarto argomento comporterà una corrispondenza senza distinzione tra maiuscole e minuscole. MA, usando solo "re.I" come quarto argomento non risulta una corrispondenza senza distinzione tra maiuscole e minuscole.

Per confronto,

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

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

re.findall(r'treeroot', old)

[ 'Treeroot']


Questo non fornisce una risposta alla domanda. Si prega di modificare la risposta per garantire che essa migliora altre risposte già presenti in questa domanda.
hongsy,

1

Stavo per essere convertito nelle sequenze di escape (scorrere un po 'verso il basso), quindi ho notato che re.sub converte i caratteri di escape con backslash in sequenze di escape.

Per evitare che ho scritto quanto segue:

Sostituire la distinzione tra maiuscole e minuscole.

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

Inoltre, se si desidera che venga sostituito con i caratteri di escape, come le altre risposte qui che ottengono il significato speciale di caratteri bashslash convertiti in sequenze di escape, basta decodificare la ricerca e, o sostituire la stringa. In Python 3, potrebbe essere necessario eseguire operazioni come .decode ("unicode_escape") # python3

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

Testato in Python 2.7.8

Spero che aiuti.


0

non ho mai pubblicato una risposta prima e questo thread è davvero vecchio ma ho avuto un altro sollution e ho pensato che potrei ottenere la tua risposta, non sono esperto nella programmazione di Python, quindi se ci sono degli svantaggi apparenti ad esso, per favore segnalali dal suo buon apprendimento: )

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
Per l'apprendimento: generalmente quando si esegue una ricerca e si sostituisce una stringa, è meglio non prima trasformarla in un array. Ecco perché la prima risposta è probabilmente la migliore. Mentre utilizza un modulo esterno, tratta la stringa come una stringa intera. È anche un po 'più chiaro cosa sta succedendo nel processo.
Isaaclw,

Per l'apprendimento: è molto difficile per uno sviluppatore senza contesto leggere questo codice e decifrare cosa sta facendo :)
Todd,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.