• Aucun résultat trouvé

Opérations de base sur les chaînes

5.4 Complément : la récursion

6.2.2 Opérations de base sur les chaînes

6.2.2.1 Construction La première question que l’on se pose sur les chaînes de caractères est la suivante :

Comment créer une chaîne de caractères ?

On peut distinguer les constructions simples par des expressions atomiques de chaînes et les constructions complexes par des expressions de concaténation.

6.2.2.1.1 Expressions atomiques de chaînes Comme indiqué lors du premier cours, les chaînes de caractères peuvent être construites directement par une expression atomique correspondant à une suite de caractères encadrée par des guillemets simples (') ou doubles ("). Pour construire la chaîne de caractères :

Ceci est une chaîne on peut donc écrire :

>>> 'Ceci est une chaîne'

'Ceci est une chaîne'

Remarquons au passage que le type d’une chaîne est bienstr. >>> type('Ceci est une chaîne')

str

>>> "Ceci est une chaîne"

'Ceci est une chaîne'

On remarque ici que Python répond toujours avec des guillemets simples, sauf si la chaîne contient elle-même une guillemet simple.

On a d’ailleurs deux façons principales d’écrire une chaîne contenant une guillemet simple : Première solution - en encadrant par des guillemets doubles :

>>> "l'apostrophe m'interpelle"

"l'apostrophe m'interpelle"

Deuxième solution - en utilisant un antislash \ (barre oblique inversée) devant la guillemet simple faisant partie de la chaîne :

>>> 'l\'apostrophe m\'interpelle'

"l'apostrophe m'interpelle"

On remarque dans ce dernier cas que Python «préfère» encadrer par des guillemets doubles, ce qui est effectivement plus lisible.

Exercice : proposer deux façons différentes de construire une chaîne contenant des guillemets doubles.

Remarque : Contrairement à d’autres langages de programmation (comme le C, Java, etc.), le langage Python ne fait pas la différence entre caractère et chaîne de un seul caractère.

>>> 'a'

'a'

>>> type('a')

str

Il existe aussi la chaîne vide qui n’est composée d’aucun caractère : >>> ''

''

Attention : il ne faut pas confondre les chaînes avec les autres types comme int ou float >>> type('234')

str

>>> type(234)

int

Nous allons voir notamment que l’opérateur+ possède une signification bien différente dans le cas des chaînes.

>>> 2 + 3 5

>>> '2' + '3'

'23'

6.2.2.1.2 Construction par concaténation Pour construire des chaînes «complexes» à partir de chaînes «plus simples», on utilise le plus souvent l’opérateur + qui réalise la concaténation de deux ou plusieurs chaînes de caractères.

La signature de cette opérateur est la suivante : str * str -> str

Par exemple :

>>> 'alu' + 'minium'

'aluminium'

L’opérateur de concaténation est dit associatif, de sorte que pour toutes chaînes c1, c2 et c3 :

c1 + ( c2+ c3) == ( c1+ c2) + c3 == c1 + c2 + c3

>>> 'ainsi parlait ' + 'Zara' + 'thoustra'

'ainsi parlait Zarathoustra'

Un petit point de terminologie. On dit que la chaîne finale'ainsi parlait Zarathoustra’ est le résultat de la concaténation des trois sous-chaînes'ainsi parlait ', 'Zara' et 'thoustra' (dans cet ordre).

En revanche, contrairement à l’addition numérique, l’opérateur de concaténation n’est pas commutatif :

>>> 'bon' + 'jour'

'bonjour'

>>> 'jour' + 'bon'

'jourbon'

Une autre propriété importante de l’opérateur de concaténation est qu’il a pour élément neutre la chaîne vide, ainsi :

>>> '' + 'droite'

>>> 'gauche' + ''

'gauche'

Autrement dit, pour toute chaîne c on a les égalités suivantes : c == (c+'') == (''+ c)

Pour illustrer l’utilisation de l’opérateur de concaténation, considérons le problème de construc- tion de chaînes suivant. On souhaite définir une fonctionrepetition le but est de faire «bégayer» des chaînes de caractères.

Par exemple :

>>> repetition('bla', 3)

'blablabla'

>>> repetition('zut ! ', 5)

'zut ! zut ! zut ! zut ! zut ! '

Une définition pour cette fonction est proposée ci-dessous : def repetition(s, n):

""" str * int -> str Hypothèse : n >= 1

retourne la chaîne composée de n répétitions successives de la chaîne s.""" # r : str

r = '' # on initialise avec la chaîne vide puisque c'est l'élément neutre # i : int (caractère courant)

for i in range(1, n + 1): r = r + s

return r

# jeu de tests

assert repetition('bla', 3) == 'blablabla'

# cf. égalité sur les chaînes un peu plus loin ...

assert repetition('zut ! ', 5) == 'zut ! zut ! zut ! zut ! zut ! '

Pour illustrer le fonctionnement de repetition, considérons la simulation correspondant à l’appelrepetition('bla', 3) donc avec s='bla' et n=3.

tour de boucle variablei variabler

tour de boucle variablei variabler

1er 1 'bla'

2e 2 'blabla'

3e 3 'blablabla'

sortie - 'blablabla'

Remarque : La fonction repetition est en fait prédéfinie en Python, sous la forme de l’opérateur*.

Par exemple : >>> 'bla' * 3

'blablabla'

>>> 'zut ! ' * 5

'zut ! zut ! zut ! zut ! zut ! '

6.2.2.2 Déconstruction Maintenant que nous savons comment construire des chaînes, de façon directe ou grâce à une fonction commerepetition, découvrons le procédé inverse qui consiste à déconstruire (ou décomposer) une chaîne en sous-chaînes ou en caractères (sous-chaînes de 1 caractère).

6.2.2.2.1 Déconstruction en caractères L’opération de déconstruction la plus basique consiste à accéder aui-ème caractère d’une chaîne s par la syntaxe suivante :

s[i]

Chaque caractère d’une chaîne possède un indice unique permettant de le repérer. Pour la chaîne'Salut, ça va ?' les indices sont les suivants :

Caractère S a l u t ç a v a ?

Indice 0 1 2 3 4 5 6 7 8 9 10 11 12

Comme c’est souvent le cas en informatique, les indices sont comptés à partir de zéro, ainsi : — le premier caractère se trouve à l’indice 0, c’est donc le 0-ième caractère

— le second caractère se trouve à l’indice 1, c’est donc le 1-ième caractère — etc.

Confirmons en pratique ces valeurs : >>> # ch : str

... ch = 'Salut ça va ?'

Nous n’effectuerons aucune affectation sur cette variable donc son contenu sera toujours la chaîne'Salut ça va ?'.

>>> ch[0] 'S' >>> ch[1] 'a' >>> ch[9] 'v' >>> ch[12] '?'

Attention : si on accède à un indice au-delà du dernier caractère, une erreur est signalée. >>> ch[13]

---

IndexError Traceback (most recent call last)

... ----> 1 ch[13]

IndexError: string index out of range

Exercice - donner le résultat des appels suivants : — ch[8]

— ch[7] — ch[21]

Les indices négatifs, cependant, ont une signification particulière : s[-i]

retourne le (i − 1)-ème caractère en partant de la fin, ainsi : — s[-1] retourne le dernier caractère de la chaîne, — s|-2] retourne l’avant-dernier caractère, — etc.

Complétons notre table des indices :

Caractère S a l u t ç a v a ?

Indice (normal) 0 1 2 3 4 5 6 7 8 9 10 11 12 Indice (inverse) -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1

>>> ch[-1] '?' >>> ch[-7] 'ç' >>> ch[-13] 'S'

Encore une fois, il ne faut pas utiliser d’indice négatif qui tenterait d’accéder avant le premier caractère :

>>> ch[-14]

---

IndexError Traceback (most recent call last)

... ----> 1 ch[-14]

IndexError: string index out of range

Exercice - donner le résultat des appels suivants : — ch[-11]

— ch[-9] — ch[-21]

6.2.2.2.2 Découpage de chaîne Une opération plus générale que l’accès à un caractère par son index consiste à effectuer un découpage (slice en anglais) d’une chaînes par la syntaxe suivante :

s[i : j]

qui retourne la sous-chaîne de s située entre les indices i (inclus) et j (non-inclus). Voici quelques exemples (toujours sur notre chaîne référencée par la variablech) : >>> ch[2:9]

'lut ça '

>>> ch[9:11]

>>> ch[9:13]

'va ?'

Exercice - donner le résultat des appels suivants : — ch[1:7]

— ch[4:13] — ch[7:8]

Que pensez-vous de la dernière expression ? Peut-on la simplifier ?

Nous verrons lors du prochain cours (sur les listes) que les découpages de séquences (donc de chaînes) peuvent être beaucoup plus complexes mais pour l’instant nous nous limiterons aux découpages simples comme ci-dessus.

6.2.2.3 Comparaison de chaînes Les séquences comme les chaînes de caractères (ou même les intervalles même si cela représente peu d’intérêt en pratique) peuvent être comparées entre elles, en particulier pour l’égalité et l’inégalité. Les opérateurs sont les mêmes que pour les autres types de données :

<chaîne1> == <chaîne2>

retourne True si les deux chaînes sont identiques, c’est-à-dire qu’elles contiennent exactement les mêmes caractères aux mêmes indices, etFalse sinon.

<chaîne1> != <chaîne2> retourne l’inverse, c’est-à-dire :

not (<chaîne1> == <chaîne2>)

Par exemple :

>>> 'Ceci est une chaîne' == 'Ceci est une autre chaîne' False

>>> 'Ceci est une chaîne' != 'Ceci est une autre chaîne' True

Remarque : les lettres minuscules et majuscules sont distinguées dans les comparaisons. >>> 'c' == 'C'

>>> 'Ceci est une chaîne' == 'ceci est une chaîne' False

6.2.2.3.1 Complément : comparateurs d’ordre sur les chaînes de caractères Au delà de l’égalité et de l’inégalité, on peut comparer des chaînes (et plus généralement des séquences) selon un ordre défini par la norme Unicode et qui correspond à peu près à l’ordre lexicographique du dictionnaire.

L’opérateur principal est le suivant : <chaîne1> < <chaîne2>

Retourne vrai (True) si la <chaîne1> est “strictement inférieure” à la <chaîne2>

Dans l’ordre lexicographique, le caractère ‘a’ est par exemple inférieur à ‘b’ (tout comme ‘a’ est avant ‘b’ dans le dictionnaire).

>>> 'a' < 'b' True

— Si une chaîne commence par un caractère inférieur au premier caractère d’une seconde chaîne, alors la première chaîne est inférieure à la deuxième. On retrouve ici un ordre équivalent à celui des mots dans un dictionnaire.

>>> 'azozo' < 'baba' True

On remarque ici que la chaîne la plus longue est inférieure à l’autre. L’important ici est que le premier caractèrea est inférieur à b. Cet ordre se propage à la chaîne complète.

— Si les deux chaînes commencent par le même caractère, alors la comparaison se propage au deuxième caractère, et ainsi de suite.

>>> 'abab' < 'acab' True

>>> 'abcab' < 'abcb' True

— Si la première chaîne préfixe la seconde (tous les caractères sont identiques), alors elle est inférieure si elle est de longueur inférieure.

>>> 'abcdef' < 'abcdefg' True

>>> 'abcdef' < 'abcdef' # égales

False

>>> 'baba' < 'ac' # premier caractère plus grand

False

Les opérateurs dérivés de comparaisons sont les suivants : — inférieur ou égal

<chaîne1> <= <chaîne2>

Retourne la même valeur que(<chaîne1> < <chaîne2>) or (<chaîne1> == <chaîne2>) — supérieur strict

<chaîne1> > <chaîne2>

Retourne la même valeur que<chaîne2> < <chaîne1> — supérieur ou égal

<chaîne1> >= <chaîne2>

Retourne la même valeur que(<chaîne1> > <chaîne2>) or (<chaîne1> == <chaîne2>)