Qual é a maneira mais fácil de fazer uma substituição de string que não diferencia maiúsculas de minúsculas no Python?
Qual é a maneira mais fácil de fazer uma substituição de string que não diferencia maiúsculas de minúsculas no Python?
Respostas:
O string
tipo não suporta isso. Provavelmente é melhor usar o sub-método de expressão regular com a opção 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'
'hippo'
, mas seria útil se o valor de substituição fosse passado para uma função, por isso é realmente mais um bom exemplo do que qualquer outra coisa.
re.escape
usar sua agulha, há outra armadilha aqui, que esta resposta falha em evitar, observada em stackoverflow.com/a/15831118/1709587 : como os re.sub
processos escapam das seqüências, conforme observado em docs.python.org/library/re.html#re .sub , você precisa escapar de todas as barras invertidas na cadeia de substituição ou usar uma lambda.
import re
pattern = re.compile("hello", re.IGNORECASE)
pattern.sub("bye", "hello HeLLo HELLO")
# 'bye bye bye'
re.sub('hello', 'bye', 'hello HeLLo HELLO', flags=re.IGNORECASE)
re.sub
apenas suporta este sinalizador desde o Python 2.7.
Em uma única linha:
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'
Ou use o argumento opcional "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'
Continuando na resposta do bFloch, essa função mudará não uma, mas todas as ocorrências antigas com as novas - de uma maneira que não faz distinção entre maiúsculas e minúsculas.
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
Como Blair Conrad diz que string.replace não suporta isso.
Use o regex re.sub
, mas lembre-se de escapar primeiro da cadeia de substituição. Observe que não há opção de sinalizadores no 2.6 para re.sub
, então você terá que usar o modificador incorporado'(?i)'
(ou um objeto RE, consulte a resposta de Blair Conrad). Além disso, outra armadilha é que o sub processará escapes de barra invertida no texto de substituição, se uma string for fornecida. Para evitar isso, pode-se passar um lambda.
Aqui está uma função:
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'
Esta função usa as funções str.replace()
e re.findall()
. Ele substituirá todas as ocorrências de pattern
in string
por repl
uma maneira que não diferencia maiúsculas de minúsculas.
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
Isso não requer 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):]
Uma observação interessante sobre detalhes e opções de sintaxe:
Python 3.7.2 (tags / v3.7.2: 9a3ffc0492, 23 de dezembro de 2018, 23:09:28) [MSC v.1916 de 64 bits (AMD64)] no win32
import re
old = "TREEROOT treeroot TREerOot"
re.sub(r'(?i)treeroot', 'grassroot', old)
«grassroot grassroot grassroot»
re.sub(r'treeroot', 'grassroot', old)
«TREEROOT base TREerOot»
re.sub(r'treeroot', 'grassroot', old, flags=re.I)
«grassroot grassroot grassroot»
re.sub(r'treeroot', 'grassroot', old, re.I)
«TREEROOT base TREerOot»
Portanto, o prefixo (? I) na expressão de correspondência ou a adição de "flags = re.I" como quarto argumento resultará em uma correspondência que não diferencia maiúsculas de minúsculas. MAS, usar apenas "re.I" como o quarto argumento não resulta em correspondência que não diferencia maiúsculas de minúsculas.
Para comparação,
re.findall(r'treeroot', old, re.I)
['TREEROOT', 'treeroot', 'TREerOot']
re.findall(r'treeroot', old)
['treeroot']
Como estava sendo convertido para as seqüências de escape (role um pouco para baixo), observei que re.sub converte caracteres de escape com barra invertida para escapar de seqüências.
Para impedir que eu escrevi o seguinte:
Substitua maiúsculas e minúsculas.
import re
def ireplace(findtxt, replacetxt, data):
return replacetxt.join( re.compile(findtxt, flags=re.I).split(data) )
Além disso, se você desejar que ele substitua pelos caracteres de escape, como as outras respostas aqui que estão obtendo os caracteres de bashslash com significado especial convertidos em seqüências de escape, decodifique sua localização e ou substitua a string. No Python 3, pode ser necessário fazer algo como .decode ("unicode_escape") # python3
findtxt = findtxt.decode('string_escape') # python2
replacetxt = replacetxt.decode('string_escape') # python2
data = ireplace(findtxt, replacetxt, data)
Testado em Python 2.7.8
Espero que ajude.
nunca postou uma resposta antes e este tópico é realmente antigo, mas eu vim com outra solução e achei que poderia obter sua resposta. Não sou experiente na programação Python, portanto, se houver inconvenientes aparentes, indique-os desde o seu bom aprendizado: )
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))