215 votes

Remplacement insensible à la casse

Quel est le moyen le plus simple de remplacer une chaîne de caractères sans tenir compte de la casse en Python ?

253voto

Blair Conrad Points 56195

El string ne supporte pas cela. Il est probablement préférable d'utiliser la méthode de sous expression régulière avec le re.IGNORECASE option.

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

Si vous ne faites qu'un seul remplacement, ou si vous voulez économiser des lignes de code, il est plus efficace d'utiliser une seule substitution avec re.sub et le drapeau (?i) : re.sub('(?i)' + re.escape('hippo'), 'girafe', 'Je veux un hIPpo pour mon anniversaire')

3 votes

Pourquoi re.escape pour une chaîne de lettres uniquement ? Merci.

10 votes

@Elena, ce n'est pas nécessaire pour 'hippo' mais serait utile si la valeur à remplacer était transmise à une fonction. Il s'agit donc plus d'un bon exemple que d'autre chose.

99voto

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

27 votes

Ou une phrase : re.sub('hello', 'bye', 'hello HeLLo HELLO', flags=re.IGNORECASE)

1 votes

Notez que re.sub ne prend en charge ce drapeau que depuis Python 2.7.

55voto

viebel Points 1990

En une seule ligne :

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 bien, utilisez l'argument facultatif "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'

21voto

rsmoorthy Points 830

Dans le prolongement de la réponse de bFloch, cette fonction remplacera non pas une, mais toutes les occurrences de l'ancien par le nouveau, sans tenir compte de la casse.

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

3 votes

Très bien fait. Bien mieux que la regex ; elle gère toutes sortes de caractères, alors que la regex est très pointilleuse sur tout ce qui n'est pas alphanumérique. Réponse préférée IMHO.

0 votes

Tout ce que vous avez à faire est d'échapper la regex : la réponse acceptée est beaucoup plus courte et plus facile à lire que cela.

0 votes

L'échappement ne fonctionne que pour la correspondance, les barres obliques inversées dans la destination peuvent encore tout gâcher.

6voto

bFloch Points 61

Cela ne nécessite pas de 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 votes

Bonne idée, mais cela ne change pas toutes les occurrences de l'ancien avec le nouveau, mais seulement la première occurrence.

6 votes

C'est moins lisible que la version regex. Pas besoin de réinventer la roue ici.

0 votes

Il serait intéressant de faire une comparaison des performances entre cette version et celles qui ont été approuvées, elle pourrait être plus rapide, ce qui est important pour certaines applications. Ou elle pourrait être plus lente parce qu'elle fait plus de travail en Python interprété.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X