Groß- und Kleinschreibung nicht ersetzen

173

Was ist der einfachste Weg, um in Python die Zeichenfolge ohne Berücksichtigung der Groß- und Kleinschreibung zu ersetzen?

Adam Ernst
quelle

Antworten:

217

Der stringTyp unterstützt dies nicht. Verwenden Sie am besten die Submethode für reguläre Ausdrücke mit der Option 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'
Blair Conrad
quelle
11
Wenn Sie nur ein einziges Ersetzen durchführen oder Codezeilen speichern möchten, ist es effizienter, eine einzelne Ersetzung mit re.sub und dem Flag (? I) zu verwenden: re.sub ('(? I)' + re .escape ('Nilpferd'), 'Giraffe', 'Ich möchte eine HIPPO zu meinem Geburtstag')
D Coetzee
3
Warum nur für eine Buchstabenfolge entkommen ? Vielen Dank.
Elena
8
@Elena, es wird nicht benötigt 'hippo', wäre aber nützlich, wenn der zu ersetzende Wert an eine Funktion übergeben würde, also ist es wirklich mehr ein gutes Beispiel als alles andere.
Blair Conrad
2
Abgesehen davon, dass Sie re.escapeIhre Nadel benötigen , gibt es hier eine weitere Falle, die mit dieser Antwort nicht vermieden werden kann. Diese wird in stackoverflow.com/a/15831118/1709587 vermerkt : Da re.subProzesse Sequenzen entgehen, wie in docs.python.org/library/re.html#re angegeben .sub , müssen Sie entweder alle Schrägstriche in Ihrem Ersatz - String zu entkommen oder ein Lambda verwenden.
Mark Amery
84
import re
pattern = re.compile("hello", re.IGNORECASE)
pattern.sub("bye", "hello HeLLo HELLO")
# 'bye bye bye'
Unbekannt
quelle
17
Oder re.sub('hello', 'bye', 'hello HeLLo HELLO', flags=re.IGNORECASE)
Louis Yang
Beachten Sie, dass re.subdieses Flag nur seit Python 2.7 unterstützt wird.
Fuenfundachtzig
47

In einer einzigen Zeile:

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'

Oder verwenden Sie das optionale Argument "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'
viebel
quelle
14

Wenn Sie die Antwort von bFloch fortsetzen, ändert diese Funktion nicht nur eine, sondern alle Vorkommen von Altem mit Neuem - in einer Weise, in der die Groß- und Kleinschreibung nicht berücksichtigt wird.

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
rsmoorthy
quelle
Sehr gut gemacht. Viel besser als Regex; Es behandelt alle Arten von Zeichen, während der reguläre Ausdruck bei allem, was nicht alphanumerisch ist, sehr pingelig ist. Bevorzugte Antwort IMHO.
Fyngyrz
Alles, was Sie tun müssen, ist der Regex zu entkommen: Die akzeptierte Antwort ist viel kürzer und leichter zu lesen.
Mad Physicist
Escape funktioniert nur zum Abgleichen, Backslashes im Ziel können die Dinge noch durcheinander bringen.
ideasman42
4

Wie Blair Conrad sagt, unterstützt string.replace dies nicht.

Verwenden Sie den regulären Ausdruck re.sub, aber denken Sie daran, zuerst die Ersatzzeichenfolge zu maskieren. Beachten Sie, dass es in 2.6 für keine Flags-Option gibt re.sub, daher müssen Sie den eingebetteten Modifikator verwenden '(?i)'(oder ein RE-Objekt, siehe Blair Conrads Antwort). Eine weitere Gefahr besteht darin, dass Sub Backslash-Escapezeichen im Ersatztext verarbeitet, wenn eine Zeichenfolge angegeben wird. Um dies zu vermeiden, kann man stattdessen ein Lambda abgeben.

Hier ist eine Funktion:

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'
johv
quelle
4

Diese Funktion verwendet sowohl die str.replace()als auch die re.findall()Funktionen. Es wird alle Vorkommen von patternin stringmit repleiner Groß- und Kleinschreibung nicht berücksichtigen.

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
Nico Bako
quelle
3

Dies erfordert kein 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):] 
bFloch
quelle
3
Gut, aber dies ändert nicht alle Vorkommen von Altem mit Neuem, sondern nur das erste Vorkommen.
rsmoorthy
5
Es ist weniger lesbar als die Regex-Version. Hier muss das Rad nicht neu erfunden werden.
Johannes Bittner
Es wäre interessant, einen Leistungsvergleich zwischen dieser und der aktualisierten Version durchzuführen. Dies könnte schneller sein, was für einige Anwendungen von Bedeutung ist. Oder es ist langsamer, weil es in interpretiertem Python mehr Arbeit leistet.
D Coetzee
2

Eine interessante Beobachtung zu Syntaxdetails und -optionen:

Python 3.7.2 (tags / v3.7.2: 9a3ffc0492, 23. Dezember 2018, 23:09:28) [MSC v.1916 64-Bit (AMD64)] unter win32

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

"Graswurzel Graswurzel Graswurzel"

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

'TREEROOT Graswurzel TREerOot'

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

"Graswurzel Graswurzel Graswurzel"

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

'TREEROOT Graswurzel TREerOot'

Das Präfix (? I) im Übereinstimmungsausdruck oder das Hinzufügen von "flags = re.I" als viertes Argument führt also zu einer Übereinstimmung ohne Berücksichtigung der Groß- und Kleinschreibung. ABER die Verwendung von "re.I" als viertes Argument führt nicht zu einer Übereinstimmung ohne Berücksichtigung der Groß- und Kleinschreibung.

Zum Vergleich,

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

['TREEROOT', 'Treeroot', 'TREerOot']

re.findall(r'treeroot', old)

['Baumwurzel']

Murray
quelle
Dies gibt keine Antwort auf die Frage. Bitte bearbeiten Sie Ihre Antwort, um sicherzustellen, dass sie andere Antworten verbessert, die bereits in dieser Frage enthalten sind.
Hongsy
1

Ich hatte keine Konvertierung in die Escape-Sequenzen (scrollen Sie etwas nach unten), daher habe ich festgestellt, dass re.sub umgekehrte Escape-Zeichen in Escape-Sequenzen konvertiert.

Um dies zu verhindern, habe ich folgendes geschrieben:

Ersetzen Sie die Groß- und Kleinschreibung nicht.

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

Wenn Sie möchten, dass es durch die Escape-Zeichen ersetzt wird, wie die anderen Antworten hier, bei denen die Bashslash-Zeichen mit besonderer Bedeutung in Escape-Sequenzen konvertiert werden, dekodieren Sie einfach Ihre Such- und / oder Ersetzungszeichenfolge. In Python 3 muss möglicherweise etwas wie .decode ("unicode_escape") # python3 ausgeführt werden

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

Getestet in Python 2.7.8

Hoffentlich hilft das.

Stan S.
quelle
0

Ich habe noch nie eine Antwort gepostet und dieser Thread ist wirklich alt, aber ich habe mir eine andere Lösung ausgedacht und dachte, ich könnte Ihre Antwort bekommen. Ich bin nicht in der Python-Programmierung erfahren. Wenn es also offensichtliche Nachteile gibt, weisen Sie sie bitte darauf hin, da es gut gelernt hat: )

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))
anddan
quelle
2
Zum Lernen: Wenn Sie eine Zeichenfolge suchen und ersetzen, ist es im Allgemeinen besser, sie nicht zuerst in ein Array umzuwandeln. Deshalb ist die erste Antwort wahrscheinlich die beste. Während ein externes Modul verwendet wird, wird die Zeichenfolge als eine ganze Zeichenfolge behandelt. Es ist auch etwas klarer, was dabei passiert.
isaaclw
Zum Lernen: Es ist sehr schwierig für einen Entwickler ohne Kontext, diesen Code zu lesen und zu entschlüsseln, was er tut :)
Todd