Aller au contenu

Traitement de texte

Le texte est la forme la plus courante de données que traite un programme.

DomaineExemples de données textuelles
WebPages HTML, URLs, commentaires, messages
ScienceSéquences d’ADN (ACGT), articles scientifiques, formules chimiques
SystèmesFichiers journaux, configurations, fichiers CSV
Jeux vidéoNiveaux encodés, dialogues, sauvegardes
LinguistiqueCorpus, traductions, correction orthographique

Un biologiste qui analyse une séquence d’ADN, un éditeur de jeu qui charge un niveau depuis un fichier, un data scientist qui nettoie un jeu de données — tous manipulent du texte.


Une chaîne de caractères (string) est une séquence de caractères. Le mot-clé ici est séquence — comme une liste.

sequence = "ATGCGC"
message = 'Bonjour'

Les chaînes partagent beaucoup de traits avec les listes.

OpérationListeChaîne
Longueurlen([1, 2, 3])3len("ATG")3
Accès par indiceliste[0]"ATG"[0]'A'
Tranchageliste[1:3]"ATGCGC"[1:3]'TG'
Appartenance3 in [1, 2, 3]"A" in "ATG"True
Itérationfor item in listefor char in "ATG"
Concaténation[1, 2] + [3, 4]"AT" + "GC"'ATGC'
Répétition[0] * 3[0, 0, 0]"A" * 3'AAA'
adn = "ATGCGCATGC"
print("Longueur :", len(adn))
print("Premier :", adn[0])
print("Dernier :", adn[-1])
print("Du 2e au 4e :", adn[1:4])
print("Inversée :", adn[::-1])
Longueur : 10
Premier : A
Dernier : C
Du 2e au 4e : TGC
Inversée : CGTACGCGTA

Contrairement aux listes, les chaînes sont non modifiables (immutable).

liste = [1, 2, 3]
liste[0] = 99 # OK
print(liste)
texte = "ATG"
texte[0] = "G" # TypeError !

C’est pour ça que toutes les méthodes de chaînes retournent une nouvelle chaîne plutôt que de modifier l’original.


Les méthodes de chaînes s’appellent avec la notation pointée et retournent une nouvelle chaîne.

texte = "atg cgc atg"
print(texte.upper())
print(texte.lower())
print(texte.capitalize())
print(texte.title())
ATG CGC ATG
atg cgc atg
Atg cgc atg
Atg Cgc Atg
donnees = " ATGCGC "
print("[" + donnees.strip() + "]")
print("[" + donnees.lstrip() + "]")
print("[" + donnees.rstrip() + "]")
[ATGCGC]
[ATGCGC ]
[ ATGCGC]
adn = "ATGCGCATGC"
# Remplacer toutes les occurrences
print(adn.replace("A", "a"))
# Limiter le nombre de remplacements
print(adn.replace("A", "a", 1))
aTGCGCaTGC
aTGCGCATGC

Ces deux méthodes sont inverses l’une de l’autre.

phrase = "chat chien oiseau poisson"
# split : chaîne → liste
mots = phrase.split(" ")
print(mots)
# join : liste → chaîne
rejoint = "-".join(mots)
print(rejoint)
['chat', 'chien', 'oiseau', 'poisson']
chat-chien-oiseau-poisson

Sans argument, .split() découpe sur tous les espaces blancs (espaces, tabulations, retours à la ligne).

ligne_csv = "Alice,20,88.5,A"
champs = ligne_csv.split(",")
print(champs)
['Alice', '20', '88.5', 'A']

Ces méthodes retournent un booléen (True ou False).

print("12345".isdigit())
print("ATGCGC".isalpha())
print("ABC123".isalnum())
print("ABC 123".isalnum()) # Espace n'est pas alphanumérique
True
True
True
False
MéthodeTeste si la chaîne contient
.isdigit()Uniquement des chiffres (0-9)
.isalpha()Uniquement des lettres
.isalnum()Uniquement des lettres ou chiffres
.isspace()Uniquement des espaces blancs
.isupper()Uniquement des majuscules
.islower()Uniquement des minuscules
fichier = "donnees.csv"
print(fichier.startswith("donnees"))
print(fichier.endswith(".csv"))
print(fichier.endswith((".csv", ".txt", ".json")))
True
True
True
adn = "ATGCGCATGC"
print(adn.find("GC")) # Position de la première occurrence
print(adn.find("TTT")) # -1 si non trouvé
print(adn.count("GC")) # Nombre d'occurrences
3
-1
3

adn = "ATGCGC"
for base in adn:
print(base)
A
T
G
C
G
C
adn = "ATGCGC"
for i, base in enumerate(adn):
print("Position " + str(i) + " : " + base)
Position 0 : A
Position 1 : T
Position 2 : G
Position 3 : C
Position 4 : G
Position 5 : C
adn = "ATGCGCATGCAAATTTGGG"
a = adn.count("A")
t = adn.count("T")
g = adn.count("G")
c = adn.count("C")
print("A :", a)
print("T :", t)
print("G :", g)
print("C :", c)
# Teneur en GC (importante en biologie moléculaire)
teneur_gc = (g + c) / len(adn) * 100
print("Teneur en GC : " + format(teneur_gc, ".1f") + " %")
A : 5
T : 4
G : 6
C : 4
Teneur en GC : 52.6 %

Puisque les chaînes sont immutables, “construire” une chaîne se fait par concaténation ou via une liste.

# Construire la complémentaire d'un brin d'ADN
# A ↔ T, G ↔ C
adn = "ATGCGC"
complement = []
for base in adn:
if base == "A":
complement.append("T")
elif base == "T":
complement.append("A")
elif base == "G":
complement.append("C")
elif base == "C":
complement.append("G")
resultat = "".join(complement)
print("Original :", adn)
print("Complément :", resultat)
Original : ATGCGC
Complément : TACGCG


Quand on analyse de grandes séquences (un gène complet fait des milliers de bases), les boucles Python deviennent lentes. NumPy permet des analyses vectorisées très rapides.

import numpy as np
adn = "ATGCGCATGC"
tableau = np.array(list(adn))
print(tableau)
print("Forme :", tableau.shape)
print("Type :", tableau.dtype)
['A' 'T' 'G' 'C' 'G' 'C' 'A' 'T' 'G' 'C']
Forme : (10,)
Type : <U1

list("ATGC") découpe la chaîne en caractères. np.array(...) la transforme en tableau NumPy.

On peut comparer tous les caractères à une valeur en une seule opération.

import numpy as np
adn = np.array(list("ATGCGCATGCAAATTTGGG"))
# Comparaison vectorisée : retourne un tableau de booléens
est_a = adn == "A"
print(est_a)
# Compter les True avec sum()
print("Nombre de A :", np.sum(est_a))
[ True False False False False False True False False False True True
True False False False False False False]
Nombre de A : 5

Un tableau booléen peut être sommé directement : chaque True vaut 1, chaque False vaut 0.

import numpy as np
adn = np.array(list("ATGCGCATGCAAATTTGGG"))
for base in ["A", "T", "G", "C"]:
compte = np.sum(adn == base)
print(base + " : " + str(compte))
A : 5
T : 4
G : 6
C : 4

Le résultat est identique à la version avec .count(), mais la structure s’étend naturellement à des analyses plus complexes.

import numpy as np
sequence_1 = np.array(list("ATGCGCATGC"))
sequence_2 = np.array(list("ATGCGCACGC"))
# Quelles positions diffèrent ?
differences = sequence_1 != sequence_2
print(differences)
# Nombre de différences
print("Différences :", np.sum(differences))
# Similarité en pourcentage
similarite = np.mean(sequence_1 == sequence_2) * 100
print("Similarité : " + format(similarite, ".1f") + " %")
[False False False False False False False True False False]
Différences : 1
Similarité : 90.0 %
import numpy as np
adn = np.array(list("ATGCGCATGCAAATTTGGG"))
positions_a = np.where(adn == "A")[0]
print("Positions de A :", positions_a)
Positions de A : [ 0 6 10 11 12]

np.where(condition) retourne les indices où la condition est vraie. C’est l’équivalent vectorisé d’un for avec if.


OpérationOutilExemple
Découper.split()"a,b,c".split(",")["a","b","c"]
Rejoindre.join()"-".join(["a","b"])"a-b"
Remplacer.replace()"ATG".replace("A","a")"aTG"
Compter.count()"ATGA".count("A")2
Vérifier.isdigit(), etc."123".isdigit()True