Manipuler du texte

Et si nous apprenions maintenant à Python à parler ?
Nous nous efforçons à parler sa langue, ce serait bien qu’il fasse aussi un pas vers nous.

Chaînes de caractères

Nous n’avons jusqu’ici manipulé que des nombres, mais ce ne sont pas les seuls types de données utilisables en Python, bien heureusement. Bien que la mémoire de l’ordinateur ne sache traiter que des nombres, les langages de programmation offrent des abstractions pour représenter d’autres données.

Ainsi Python sait associer chaque lettre ou chaque caractère à un nombre grâce aux tables d’encodage. Et le texte, ce n’est au final qu’une suite de lettres, une séquence de caractères. On parle alors d’une chaîne de caractères.

On définit une chaîne de caractères à l’aide d’une paire de guillemets (double-quotes), entre lesquels on place le texte voulu.

>>> "Salut les gens !"
'Salut les gens !'

On voit Python nous répondre par cette même chaîne délimitée par des apostrophes (quotes). Il s’agit juste de deux syntaxes équivalentes pour représenter la même chose : une chaîne peut être délimitée par des apostrophes ou des guillemets, cela revient au même.

>>> 'toto'
'toto'
>>> "toto"
'toto'

Les chaînes de caractères sont un type de valeur et donc des expressions, qu’il est possible d’assigner à des variables.

>>> text = 'toto'

Si l’on appelle print sur une chaîne de caractères, son contenu est simplement affiché sur le terminal, sans les délimiteurs.

>>> print(text)
toto
>>> print('Salut les gens !')
Salut les gens !

L’avantage des deux syntaxes pour délimiter les chaînes, c’est qu’il est possible d’entourer la chaîne d’apostrophes pour lui faire contenir des guillemets, et inversement.

>>> 'Il a dit "salut"'
'Il a dit "salut"'
>>> "Oui il l'a dit"
"Oui il l'a dit"

Autrement, on aurait le droit à de belles erreurs car Python penserait en rencontrant le premier guillemet que l’on termine la chaîne, et il ne comprendrait donc pas les caractères qui suivraient.

>>> "Il a dit "salut""
  File "<stdin>", line 1
    "Il a dit "salut""
                   ^
SyntaxError: invalid syntax

Mais comment alors représenter une chaîne de caractères possédant à la fois des apostrophes et des guillemets (telle que J'ai dit "salut") ? La solution se situe au niveau de l’échappement. Il suffit de faire précéder un caractère d’un backslash (ou antislash, \) pour qu’il ne soit pas interprété par Python comme un caractère de délimitation.

>>> 'J\'ai dit "salut"'
'J\'ai dit "salut"'

Ces échappements, comme les délimiteurs, disparaissent lorsque le texte est affiché à l’aide d’un print.

>>> print('J\'ai dit "salut"')
J'ai dit "salut"

D’autres séquences d’échappement sont disponibles, comme \t pour représenter une tabulation (alinéa) ou \n pour un saut de ligne (n comme newline, soit nouvelle ligne). Il n’est en effet pas possible de revenir à la ligne dans une chaîne de caractères, et le \n est donc nécessaire pour insérer un saut de ligne.

>>> print('Elle a dit :\t"Salut"')
Elle a dit :	"Salut"
>>> print('Première ligne\nDeuxième ligne')
Première ligne
Deuxième ligne

Certains systèmes d’exploitation comme Windows pourraient ne pas bien interpréter le \n comme un saut de ligne et demander à ce qu’il soit précédé du caractère « retour-chariot » (\r) pour fonctionner.

>>> print('Une\r\nDeux')
Une
Deux

C’est un héritage de l’époque des machines à écrire où il fallait à la fois passer à la ligne suivante (nouvelle ligne) et revenir en début de ligne (retour chariot).

Et enfin, le backslash étant lui-même un caractère spécial, il est nécessaire de l’échapper (donc le doubler) si on veut l’insérer dans une chaîne. Comme par exemple pour un chemin de fichier sous Windows :

>>> print('C:\\Python\\projet\\example.py')
C:\Python\projet\example.py

Afin de moins avoir recours aux séquences d’échappement, il est aussi possible d’utiliser des triple-quotes pour définir une chaîne de caractères. Il s’agit de délimiter notre chaîne par trois apostrophes (ou trois guillemets) de chaque côté, lui permettant alors d’utiliser librement apostrophes et guillemets à l’intérieur, mais aussi des retours à la ligne.

>>> print('''J'ai dit "salut"''')
J'ai dit "salut"
>>> print("""Une chaîne sur
... plusieurs lignes
... avec des ' et des " dedans""")
Une chaîne sur
plusieurs lignes
avec des ' et des " dedans

On voit des ... apparaître à la place des >>> dans l’interpréteur interactif.
Cela signifie que l’interpréteur ne peut pas exécuter telle quelle la ligne de code entrée et qu’il attend pour cela les lignes suivantes, qui complèteront le code.

Opérations sur les chaînes

Une chaîne de caractères est une valeur à part entière, et comme toute valeur elle a certaines opérations qui lui sont applicables.

Pour commencer, la fonction len est une fonction de base de Python, qui peut être appelée avec une chaîne de caractères en argument. La fonction renvoie un nombre entier représentant la longueur de la chaîne, c’est-à-dire le nombre de caractères qu’elle contient.

>>> len('Hello')
5
>>> len('Hello World!')
12

C’est une fonction assez utile puisqu’elle nous permet par exemple de calculer l’espace occupé à l’écran par notre texte.

Mais d’autres opérations agissent directement sur le texte. C’est le cas de l’opérateur d’addition (+) que nous avons vu pour les nombres et qui existe aussi pour le texte, mais pour lequel il a un sens un peu différent.

On ne va en effet pas additionner deux chaînes de caractères, ça n’aurait pas de sens, mais on va les mettre l’une à la suite de l’autre. On appelle cette opération une concaténation.

>>> 'Hello' + ' ' + 'World' + '!'
'Hello World!'

Les délimiteurs ne faisant pas partie de la chaîne, il est bien sûr possible de mixer des chaînes délimitées par des apostrophes avec d’autres délimitées par des guillemets.

>>> 'abc' + "def"
'abcdef'

Nous retrouvons aussi l’opérateur de multiplication * pour représenter un autre type de concaténation : la répétition d’une chaîne un certain nombre de fois. 'to' * 3 est ainsi équivalent à 'to' + 'to' + 'to'.

>>> 'to' * 3
'tototo'

On peut multiplier un texte par un nombre nul ou négatif, cela a pour effet de produire une chaîne vide. En revanche multiplier une chaîne par un nombre flottant n’a aucun sens, et Python nous le fait bien comprendre.

>>> 'toto' * 0
''
>>> 'toto' * -10
''
>>> 'toto' * 1.5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'float'

Toutes les facilités vues jusqu’ici avec les opérateurs d’assignation restent bien sûr valables.

>>> msg = 'Salut '
>>> msg += 'tom'*2 + ' et ' + 'na'*2
>>> print(msg)
Salut tomtom et nana

Mais nous découvrons aussi d’autres opérateurs que nous n’avions pas vus jusque-là, pour des opérations spécifiques à ce nouveau type de données.
Les chaînes de caractères formant une séquence d’éléments (des caractères), il est possible d’accéder de façon directe à chacun de ces éléments.

Cela se fait à l’aide de crochets ([ ]) en indiquant entre eux la position du caractère voulu, par exemple msg[3].
Il faut savoir que généralement en informatique on compte à partir de 0. Le premier caractère d’une chaîne se trouve donc à la position 0 de la séquence, le deuxième caractère à la position 1, etc. jusqu’au n-ième caractère à la position n-1.

>>> msg = 'Salut'
>>> msg[0]
'S'
>>> msg[0] + msg[1] + msg[2] + msg[3] + msg[4]
'Salut'

La valeur 'S' renvoyée par msg[0] est un caractère, c’est-à-dire en Python une chaîne de taille 1.

On peut alors représenter notre chaîne de caractères 'Salut' sous la forme d’un tableau, associant une position (un index) à chaque caractère de la chaîne :

Index Caractère
0 's’
1 'a'
2 'l'
3 'u'
4 't'

Il est ainsi possible d’accéder à n’importe quel caractère de la chaîne à partir de son index, s’il est compris dans les bornes (de 0 à len(msg)-1).

>>> msg[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

On observe qu’au-delà on obtient une erreur IndexError, soit un index invalide. On peut en revanche utiliser des index négatifs pour prendre la chaîne en sens inverse : -1 correspond au dernier caractère, -2 à l’avant-dernier, jusqu’à -len(msg) pour le premier. Chaque caractère a ainsi deux positions possibles dans la chaîne.

>>> msg[-1]
't'
>>> msg[-3]
'l'
>>> msg[-5]
'S'
Index Caractère
-5 's’
-4 'a'
-3 'l'
-2 'u'
-1 't'