Kurs
Es ist verlockend, zu .find() oder .index() zu greifen, um zu prüfen, ob Text in einem String vorkommt — und dann über Kuriositäten wie einen ValueError oder einen verpassten Treffer am Stringanfang zu stolpern. Groß-/Kleinschreibung, Off-by-one-Slice-Grenzen und die Tatsache, dass es keine .contains()-Methode auf str gibt, verstärken die Verwirrung. Die Lösung ist simpel: das passende Werkzeug wählen. Für Existenzprüfungen nutzen wir den Operator in, für Positionen .find()/.index(), für Zählungen .count() und für Ersetzungen .replace() — ergänzt um ein paar Unicode-sichere Techniken, wenn Groß-/Kleinschreibung egal ist.
Wie Python die Suche nach Teilstrings handhabt
Pythons Text-Strings sind Unicode. Teilstring-Operationen sind standardmäßig case-sensitiv und in C implementiert, um schnell zu sein. Der direkteste Weg zu testen, ob Text in einem String vorkommt, ist der Operator in, der ein Boolean zurückgibt und die __contains__()-Implementierung des Strings nutzt. Wenn du Positionen oder Zählwerte brauchst, nimm die entsprechenden str-Methoden. Optionale Parameter start und end folgen der Slice-Semantik: Start ist inklusiv, Ende exklusiv.
Enthaltensein mit in
Verwende "needle" in haystack, wenn dich nur interessiert, ob der Teilstring existiert. Das ist gut lesbar und erspart dir Index-Handling.
text = "Banana bread"
print("ban" in text) # False (case-sensitive)
print("Ban" in text) # True
Für case-insensitive Checks normalisierst du beide Seiten. .casefold() ist Unicode-bewusster als .lower() und meine Standardwahl für vergleiche ohne Beachtung der Groß-/Kleinschreibung.
pattern = "ban"
print(pattern.casefold() in text.casefold()) # True
- Wann verwenden: schnelle Existenzchecks, Eingabevalidierung, Listen filtern.
- Sonderfall:
"" in sist immerTrue(der leere String steckt in jedem String).
Methode str.find()
Syntax
str.find() gibt den kleinsten Index des Teilstrings zurück oder -1, wenn nichts gefunden wird. Optionale start- und end-Werte schränken die Suche ein.
s.find(substring, start=0, end=len(s))
Beispiele und Anwendungsfälle
Nutze .find(), wenn du die Position brauchst und einen „nicht gefunden“-Wert ohne Exceptions verarbeiten kannst.
tagline = "Ship fast. Fix faster."
print(tagline.find("fast")) # 5
print(tagline.find("fast", 6)) # 16
print(tagline.find("slow")) # -1
Schreibe nicht if s.find(sub): für Existenzprüfungen. Steht der Treffer an Index 0, ist die Bedingung falsey.
name = "Alice"
if name.find("A"): # Falsch: 0 ist Falsey
print("Found A") # Läuft nicht
if name.find("A") != -1: # Korrekt
print("Found A")
Methode str.index()
Syntax
.index() spiegelt .find(), wirft aber einen ValueError, wenn der Teilstring fehlt.
s.index(substring, start=0, end=len(s))
Beispiele und wann du es wählst
Nutze .index(), wenn der Teilstring existieren muss und eine Exception das gewünschte Fehlersignal ist.
product = "USB-C Cable"
print(product.index("Cable")) # 6
try:
product.index("HDMI")
except ValueError:
print("Required label missing")
Methode str.count()
Syntax
.count() gibt die Anzahl nicht-überlappender Vorkommen zurück. start und end werden ebenfalls unterstützt.
s.count(substring, start=0, end=len(s))
Beispiele und Sonderfälle
Nutze .count() für schnelle Zählungen ohne Regex.
log_line = "ERROR: timeout. ERROR: retry. ERROR: gave up."
print(log_line.count("ERROR")) # 3
print(log_line.count("WARN")) # 0
Spezialfall: der leere String.
print("abc".count("")) # 4 (len(s) + 1)
Methode str.replace()
.replace() gibt einen neuen String zurück, in dem Vorkommen von old durch new ersetzt werden. Mit count begrenzt du die Anzahl der Ersetzungen.
s.replace(old, new, count=-1)
Teilstrings ersetzen
Die Methode arbeitet nicht in-place; sie liefert eine Kopie zurück.
message = "The red house is between the blue house and the old house"
print(message.replace("house", "car"))
# The red car is between the blue car and the old car
print(message.replace("house", "car", 2))
# The red car is between the blue car and the old house
Case-insensitive Ersetzungen
Für Ersetzungen ohne Beachtung der Groß-/Kleinschreibung und mit Erhalt des ursprünglichen Kasus nutze re.sub() mit re.IGNORECASE, oder normalisiere mit .casefold(), wenn dir der ursprüngliche Kasus egal ist.
Case-insensitive Abgleiche mit .casefold()
.casefold() bietet eine aggressive, Unicode-bewusste Normalisierung der Groß-/Kleinschreibung und ist .lower() für vergleiche ohne Kasusunterscheidung vorzuziehen.
query = "straße" # German 'straße'
text = "STRASSE und mehr" # Uppercase variant
print(query.casefold() in text.casefold()) # True
Verwandte Tools für Präfixe und Suffixe
Für bekannte Starts/Enden sind dedizierte Methoden die beste Wahl — schneller und klarer als Slices oder Regex:
s.startswith(prefix)unds.endswith(suffix)(akzeptieren Tupel für mehrere Optionen)
s.removeprefix(prefix)unds.removesuffix(suffix)(Python 3.9+)
filename = "draft_report_v2.pdf"
print(filename.removeprefix("draft_")) # report_v2.pdf
print(filename.endswith((".pdf", ".docx"))) # True
Arbeiten mit Pandas-Spalten
Wenn du viele Strings in einer DataFrame-Spalte durchsuchst, nutze vektorisierte String-Methoden. Setze regex=False, um wörtlichen Text zu matchen.
import pandas as pd
cities = pd.Series(["New York", "Yorktown", None, "Toronto"], dtype="string")
mask = cities.str.contains("York", regex=False, na=False)
print(mask.tolist()) # [True, True, False, False]
Hinweise:
- Standardmäßig ist
regex=True, daher matchen Sonderzeichen wie.jedes Zeichen, sofern du Regex nicht deaktivierst.
- Null-Werte über
na=...steuern. MitStringDtypesind fehlende Werte im Masken-Resultat standardmäßigFalse.
Häufige Fallstricke und Sonderfälle
-
Kein .contains() auf str: Nutze
"sub" in s."abc".contains("a")wirftAttributeError.
-
Wahrheitswert von .find(): Index
0ist falsey; vergleiche mit!= -1oder nutze für Existenzin.
-
.index() wirft: Behandle
ValueError, wenn der Teilstring fehlen könnte.
-
Leerer Teilstring:
"" in sistTrue;s.find("")ergibt0;s.count("")istlen(s)+1.
-
Groß-/Kleinschreibung: Alle Operationen sind case-sensitiv, sofern du nicht normalisierst oder Regex-Flags nutzt.
-
Bytes vs. Text: Mische
bytesundstrnicht in Suchen; dekodiere oder kodiere, sodass die Typen passen.
-
Teilstring-Semantik:
"ab" in "cat,bat"istFalse, obwohl"a"und"b"einzeln vorkommen — Treffer müssen zusammenhängend sein.
Hands-on-Beispiele zum Ausprobieren
Diese kurzen Snippets zeigen bewährte Muster und heben typische Stolpersteine hervor.
Existenzprüfungen
headline = "Where's Waldo?"
print("Waldo" in headline) # True
print("Wenda" in headline) # False
print(headline.find("Waldo")) # 8
print(headline.find("Wenda")) # -1
Begrenzte Suche mit start und end
Das Ende ist exklusiv, die Suchpositionen folgen also der Slice-Semantik.
headline = "Where's Waldo?"
print(headline.find("Waldo", 0, 6)) # -1 (Suche in "Where'")
print(headline.find("Waldo", 0, 13)) # 8 (Suche bis zum 'o' in Waldo)
Zählen und Ersetzen
inventory = "apple, apple, pear, apple"
print(inventory.count("apple")) # 3
print(inventory.replace("apple", "orange", 2)) # orange, orange, pear, apple
Praxisbeispiel: Strings in Python suchen und ersetzen
Dieses Beispiel verarbeitet eine Liste mit Film-Blurbs. Es zeigt Existenzprüfungen, begrenzte Suchen und sichere Ersetzungen ohne Regex.
blurbs = [
"Critics say the lead actor delivers a career-best performance.",
"Fans argue the actor actor scene was intentionally repetitive.",
"A clever cameo steals the show."
]
for blurb in blurbs:
# Check whether "actor" appears between indexes 20 and 40 (end exclusive).
window_has_actor = "actor".casefold() in blurb[20:40].casefold()
if not window_has_actor:
print("Window check: actor not found")
continue
# If "actor actor" appears, collapse to a single "actor".
if "actor actor" in blurb:
print(blurb.replace("actor actor", "actor"))
# If "actor actor actor" appears, collapse to a single "actor".
elif "actor actor actor" in blurb:
print(blurb.replace("actor actor actor", "actor"))
else:
print(blurb)
Ausgabe:
Window check: actor not found
Fans argue the actor scene was intentionally repetitive.
Window check: actor not found
Fazit
Nutze den Operator in für schlichtes Enthaltensein, .find() oder .index(), wenn du Positionen brauchst, .count() für nicht-überlappende Zählungen und .replace() für Ersetzungen. Normalisiere mit .casefold() für case-insensitive Checks und greife bei Bedarf zu dedizierten Präfix-/Suffix-Helfern. Wir vermeiden es, .find()-Ergebnisse zu Booleans zu konvertieren, und behandeln das Verhalten mit leerem Teilstring als Sonderfall — so bleibt String-Code korrekt und gut lesbar.