Cours
Il est courant d’utiliser .find() ou .index() pour vérifier si un texte existe dans une chaîne—puis de rencontrer des comportements déroutants comme un ValueError ou une correspondance manquée au début de la chaîne. La sensibilité à la casse, les bornes de tranche décalées d’un caractère, et l’absence de méthode .contains() sur str ajoutent à la confusion. Le remède est simple : utilisez l’outil adapté. Appuyez-vous sur l’opérateur in pour les vérifications d’existence, .find()/.index() pour les positions, .count() pour les décomptes et .replace() pour les remplacements—avec quelques techniques sûres pour l’Unicode lorsque l’insensibilité à la casse est importante.
Comment Python gère la recherche de sous-chaînes
Les chaînes de texte en Python sont en Unicode. Les opérations sur les sous-chaînes sont sensibles à la casse par défaut et implémentées en C pour la performance. La manière la plus directe de tester si un texte apparaît dans une chaîne est l’opérateur in, qui renvoie un booléen via l’implémentation __contains__() de la chaîne. Lorsque vous avez besoin de positions ou de décomptes, utilisez les méthodes dédiées de str. Les paramètres optionnels start et end suivent la sémantique des tranches : début inclusif ; fin exclusive.
Vérifier la présence avec in
Utilisez "needle" in haystack lorsque vous voulez seulement savoir si la sous-chaîne existe. C’est lisible et évite la gestion des index.
text = "Banana bread"
print("ban" in text) # False (case-sensitive)
print("Ban" in text) # True
Pour des vérifications insensibles à la casse, normalisez les deux côtés. .casefold() est plus conscient de l’Unicode que .lower() et c’est mon choix par défaut pour les comparaisons sans casse.
pattern = "ban"
print(pattern.casefold() in text.casefold()) # True
- Quand l’utiliser : vérifications rapides d’existence, validation d’entrée, filtrage de listes.
- Cas limite :
"" in srenvoie toujoursTrue(la chaîne vide est dans toute chaîne).
Méthode str.find()
Syntaxe
str.find() renvoie le plus petit index de la sous-chaîne, ou -1 si elle n’est pas trouvée. Les paramètres facultatifs start et end restreignent la recherche.
s.find(substring, start=0, end=len(s))
Exemples et cas d’usage
Utilisez .find() lorsque vous avez besoin de la position et pouvez gérer une valeur « non trouvée » sans exceptions.
tagline = "Ship fast. Fix faster."
print(tagline.find("fast")) # 5
print(tagline.find("fast", 6)) # 16
print(tagline.find("slow")) # -1
N’écrivez pas if s.find(sub): pour vérifier l’existence. Si la correspondance est à l’index 0, la condition est falsy.
name = "Alice"
if name.find("A"): # Incorrect : 0 est falsy
print("Found A") # Ne s'exécutera pas
if name.find("A") != -1: # Correct
print("Found A")
Méthode str.index()
Syntaxe
.index() reflète .find() mais lève un ValueError lorsque la sous-chaîne est absente.
s.index(substring, start=0, end=len(s))
Exemples et quand la choisir
Utilisez .index() lorsque la sous-chaîne doit exister et qu’une exception est le bon mode d’échec.
product = "USB-C Cable"
print(product.index("Cable")) # 6
try:
product.index("HDMI")
except ValueError:
print("Required label missing")
Méthode str.count()
Syntaxe
.count() renvoie le nombre d’occurrences non superposées. Elle accepte aussi des bornes start et end.
s.count(substring, start=0, end=len(s))
Exemples et cas limites
Utilisez .count() pour des décomptes rapides sans regex.
log_line = "ERROR: timeout. ERROR: retry. ERROR: gave up."
print(log_line.count("ERROR")) # 3
print(log_line.count("WARN")) # 0
Cas particulier : la chaîne vide.
print("abc".count("")) # 4 (len(s) + 1)
Méthode str.replace()
.replace() renvoie une nouvelle chaîne où les occurrences de old sont remplacées par new. Utilisez count pour limiter le nombre de remplacements.
s.replace(old, new, count=-1)
Remplacer des sous-chaînes
La méthode n’agit pas en place ; elle renvoie une copie.
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
Remplacement insensible à la casse
Pour des remplacements insensibles à la casse tout en préservant les motifs de casse, utilisez re.sub() avec re.IGNORECASE, ou normalisez avec .casefold() si vous n’avez pas besoin de préserver la casse d’origine.
Correspondances insensibles à la casse avec .casefold()
.casefold() offre une normalisation agressive et compatible Unicode de la casse, et est préférable à .lower() pour les vérifications sans casse.
query = "straße" # German 'straße'
text = "STRASSE und mehr" # Uppercase variant
print(query.casefold() in text.casefold()) # True
Outils associés pour préfixes et suffixes
Pour des débuts/fins connus, privilégiez les méthodes dédiées—elles sont plus rapides et plus claires que les tranches ou les regex :
s.startswith(prefix)ets.endswith(suffix)(acceptent des tuples pour plusieurs options)
s.removeprefix(prefix)ets.removesuffix(suffix)(Python 3.9+)
filename = "draft_report_v2.pdf"
print(filename.removeprefix("draft_")) # report_v2.pdf
print(filename.endswith((".pdf", ".docx"))) # True
Travailler avec des colonnes Pandas
Lorsque vous cherchez dans de nombreuses chaînes d’une colonne de DataFrame, utilisez les méthodes de chaîne vectorisées. Définissez regex=False pour faire correspondre du texte littéral.
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]
Remarques :
- Par défaut,
regex=True, donc des caractères spéciaux comme.correspondent à n’importe quel caractère, sauf si vous désactivez les regex.
- Gérez les valeurs nulles via
na=.... AvecStringDtype, les valeurs manquantes valentFalsepar défaut dans le masque.
Pièges courants et cas limites
-
Pas de .contains() sur str : utilisez
"sub" in s."abc".contains("a")lèveAttributeError.
-
Véracité de .find() : l’index
0est falsy ; comparez avec!= -1ou préférezinpour l’existence.
-
.index() lève une exception : gérez
ValueErrorsi la sous-chaîne peut être absente.
-
Chaîne vide :
"" in sestTrue;s.find("")renvoie0;s.count("")vautlen(s)+1.
-
Sensibilité à la casse : toutes les opérations sont sensibles à la casse sauf si vous normalisez ou utilisez des indicateurs regex.
-
Octets vs texte : ne mélangez pas
bytesetstrdans les recherches ; décodez ou encodez pour faire correspondre les types.
-
Sémantique des sous-chaînes :
"ab" in "cat,bat"vautFalsemême si"a"et"b"apparaissent séparément—les correspondances doivent être contiguës.
Exemples pratiques à exécuter
Ces courts extraits montrent les bons modèles et mettent en évidence les pièges classiques.
Vérifications d’existence
headline = "Where's Waldo?"
print("Waldo" in headline) # True
print("Wenda" in headline) # False
print(headline.find("Waldo")) # 8
print(headline.find("Wenda")) # -1
Recherche bornée avec start et end
La fin est exclusive, donc les positions de recherche reflètent la sémantique des tranches.
headline = "Where's Waldo?"
print(headline.find("Waldo", 0, 6)) # -1 (recherche dans "Where'")
print(headline.find("Waldo", 0, 13)) # 8 (recherche jusqu'au 'o' de Waldo)
Compter et remplacer
inventory = "apple, apple, pear, apple"
print(inventory.count("apple")) # 3
print(inventory.replace("apple", "orange", 2)) # orange, orange, pear, apple
Exemple d’exercice : recherche et remplacement de chaînes en Python
Cet exemple traite une liste de critiques de films. Il illustre les vérifications d’existence, les recherches bornées et des remplacements sûrs sans 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)
Sortie :
Window check: actor not found
Fans argue the actor scene was intentionally repetitive.
Window check: actor not found
Conclusion
Utilisez l’opérateur in pour la simple appartenance, .find() ou .index() lorsque vous avez besoin des positions, .count() pour les décomptes non superposés et .replace() pour les substitutions. Normalisez avec .casefold() pour des vérifications insensibles à la casse, et préférez les aides dédiées aux préfixes/suffixes lorsque c’est pertinent. Évitez de convertir les résultats de .find() en booléens et traitez le comportement avec la sous-chaîne vide comme un cas particulier afin de garder un code sur les chaînes correct et clair.