Chaines de caractères

Les chaînes de caractères peuvent être vues comme un cas particulier de tuple.

Cas particulier d'un tuple

Une chaîne de caractères peut être vue comme un conteneur de caractères. On peut donc accéder à un caractère particulier comme une liste :


>>> "abcdefghijklmnopqrstuvwxyz"[2]
'c'

Ou même utiliser des slices de liste :

>>> "abcdefghijklmnopqrstuvwxyz"[2:15:4]
'cgko'

En revanche, il est impossible de modifier une chaîne :

>>> x = "Francois"
>>> x[4] = "ç"
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    x[4] = "ç"
    ~^^^
TypeError: 'str' object does not support item assignment
>>>

Entraînons nous un peut à manipuler les chaînes de caractères sous la forme d'un conteneur en reprenant le 23ème nombre de Mersenne sous sa forme chaîne de caractères : m23 = str(2 ** 11213 - 1).

Quels sont les 10 premiers chiffres de m23 ?

solution

str(m23)[:10]

Quels sont les 10 derniers chiffres de m23 ?

solution

str(m23)[-10:]

Est-ce que m23 est un palindrome ?

solution

str(m23) == str(m23)[::-1] (s[::-1] renverse la chaîne)

En revanche, il est interdit de modifier une chaîne de caractère :

>>> x = "chaîne"
>>> x[0] = "C"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

Enfin on ne le répétera jamais assez, python vient avec tout un tas de méthodes utilitaires permettant de résoudre nombre d'opérations courantes. Utilisez la documentation sur les méthodes de chaînes en python pour résoudre les exercices suivants :

Index de la première occurrence de 1234 dans m23. Et de la deuxième ?

solution

  • str(m23).find('1234')
  • str(m23).find('1234', 19260 + 1) : la première occurrence est à l'indice 19260, on cherche donc après.
  • on peut faire en une ligne : str(m23).find('1234', str(m23).find('1234') + 1)

byte et str

Par défaut toutes les chaînes de caractères sont de type str, et encodées en utf-8. Si on veut connaître explicitement les octets d'une chaîne, il faut l'encoder en un autre format par la méthode encode des chaînes de caractères qui rend un objet de type byte qui est une suite d'octets.

C'est comme une chaîne de caractères mais qui commence par b . On peut ensuite décoder un byte pour le retransformer en str :

x = "ma chaîne de caractères"
x_en_byte = x.encode('utf8')  # devient : b'ma cha\xc3\xaene de caract\xc3\xa8res'
re_x = x_en_byte.decode('utf8')

Ceci va s'avérer utile lorsque l'on récupérera des fichiers depuis internet. Ce seront des byte qu'il faudra re-écrire en utf8.

Les différents encoding possibles sont disponibles dans la documentation.

Méthodes des chaînes de caractères

Les chaines de caractères ont tout un tas de méthodes.

Essayons de les apprendre avec ces petits exercices :

Transformez le 23ème nombre de Mersenne ($2^{11213}-1$) en une chaîne de caractère

solution

>>> x = str(2 ** 11213 - 1)

En utilisant la méthode count, comptez le nombre de 0 du 23ème nombre de Mersenne premier.

solution

Dans un interpréteur :

>>> x.count("0")
348

En utilisant la méthode replace, changez les 2 en 7 dans le 23ème nombre de Mersenne premier.

solution

Dans un interpréteur :

>>> y = int(x.replace("2", "7"))

Avec les méthodes count, index et rindex :

Dans le 23e nombre de Mersenne :

  • combien y a-t-il de "42" ?
  • quel est l'indice du premier "42" ?
  • quel est l'indice du dernier "42" ?

solution

>>> str(2 ** 11213 - 1).count("42")
33
>>> str(2 ** 11213 - 1).index("42")
29
>>> str(2 ** 11213 - 1).rindex("42")
3327

Remplacez les 2 par des 7 dans le 23e nombre de Mersenne

solution

Attention, une fois que l'on a changer les 2 en 7 on ne peut pas juste retransformer les 7 en 2... Il faut commencer par mettre les 2 de côté puis transformer les 7 en 2 et enfin reprendre les 2 mis de coté et les transformer en 7 :

>>> x = str(2 ** 11213 - 1)
>>> y = x.replace("2","?")
>>> z = y.replace("7","2")
>>> t = z.replace("?","7")

On peut le faire en une seule ligne :

str(2 ** 11213 - 1).replace("2","x").replace("7","2").replace("x","7")

De part l'associativité à gauche, la commande précédente est équivalente à :

((str(2 ** 11213 - 1).replace("2","x")).replace("7","2")).replace("x","7")

Il est aisé de comprendre ce que ça fait en procédant de droite à gauche :

  1. replace("x","7") est appliqué à ce qui est à sa gauche donc str(2 ** 11213 - 1).replace("2","x").replace("7","2")
  2. replace("7","2") est appliqué à ce qui est à sa gauche donc str(2 ** 11213 - 1).replace("2","x")
  3. replace("2","x") est appliqué à ce qui est à sa gauche donc str(2 ** 11213 - 1)

En remontant les opérations précédentes :

  1. le résultat de str(2 ** 11213 - 1) sera une chaîne de caractère représentant le 23ème nombre premier de Mersenne
  2. str(2 ** 11213 - 1).replace("2","x") on a remplacé les 2 par des "x" dans la chaîne précédente
  3. str(2 ** 11213 - 1).replace("2","x").replace("7","2") on a remplacé les 7 par des 2 de la chaîne précédente
  4. str(2 ** 11213 - 1).replace("2","x").replace("7","2").replace("x","7") on a remplacé les "x" par des 2 dans la chaîne précédente

On a donc au final échangé les 2 et les 7 du 23ème nombre premier de Mersenne

Exercices

On utilisera les nombres de Mersenne comme prétexte à la manipulation de chaînes de caractères en python. Ces exercices sont pour une grande partie tirés d'un cours donné il y a quelques temps par Aristide Grange, à l'université Paul Verlaine de Metz.

Notez m23 le 23ième nombre de Mersenne $2^{11213} -1$ :

solution

m23 = 2 ** 11213 - 1

Combien de chiffres en base 10, 2 et 16 possède ce nombre ?

solution

  • en base 10 : len(str(m23)) : conversion de l'entier en chaîne de caractères puis son nombre de chiffres
  • en base 2 : len(bin(m23)) - 2 : bin transforme un entier en sa représentation binaire. C'est une chaîne de caractères qui commence par 0b donc on retranche 2 à la longueur.
  • en base 16 : len(hex(m23)) - 2 : hex transforme un entier en sa représentation hexadécimale. C'est une chaîne de caractères qui commence par 0x donc on retranche 2 à la longueur.

Méthodes

Utilisez la documentation sur les méthodes de chaînes en python pour résoudre les exercices suivants

Index de la première occurrence de 1234 dans m23. Et de la deuxième ?

solution

  • str(m23).find('1234')
  • str(m23).find('1234', 19260 + 1) : la première occurrence est à l'indice 19260, on cherche donc après.
  • on peut faire en une ligne : str(m23).find('1234', str(m23).find('1234') + 1)

Slice

Comme pour les listes, on peut utiliser les slices pour copier des parties de chaîne.

Ainsi "abcdefghijklmnopqrstuvwxyz"[2:15:4] vaut : 'cgko'.

Quels sont les 10 premiers chiffres de m23 ?

solution

str(m23)[:10]

Quels sont les 10 derniers chiffres de m23 ?

solution

str(m23)[-10:]

Est-ce que m23 est un palindrome ?

solution

str(m23) == str(m23)[::-1] (s[::-1] renverse la chaîne)

Chaînes formatées

On peut créer des chaînes en utilisant implicitement la concatenation en utilisant les chaines formatées (format-string ou encore f-string).

Par exemple :

>>> nom = "Ada"
>>> bonjour = f"Bonjour {nom} !"
>>> print(bonjour)
Bonjour Ada !

Remarquez le f avant le début de la chaîne, il indique à python qu'il doit remplacer l'expression entre accolade par un objet. Si on oublie le f, on obtient une chaîne classique :

>>> nom = "Ada"
>>> bonjour = "Bonjour {nom} !"
>>> print(bonjour)
Bonjour {nom} !

L'utilisation de chaînes formatées remplace une concaténation explicite :

>>> bonjour = "Bonjour " + nom + " !"
>>> print(bonjour)
Bonjour Ada !

En étant bien plus lisible.

Attention, c'est bien une concaténation à la création de la chaîne. Une chaîne ne va pas se modifier magiquement lorsque l'on modifie une variable :

>>> nom = "Ada"
>>> bonjour = f"Bonjour {nom} !"
>>> print(bonjour)
Bonjour Ada !
>>> nom = "Dominique"
>>> print(bonjour)
Bonjour Ada !

Enfin, comme les accolades sont une expression, on peut écrire ce genre de choses :

>>> réponse = f"La réponse universelle est {40 + 2}"
>>> print(réponse)
La réponse universelle est 42

Et, enfin, si on veut écrire une accolade, on l'insère : f"{'{'}".