Infoforall

PYTHON : description rapide des strings

L'objet str de Python est un objet :

Cette fiche détaille l'utilisation des strings.

1 - Description des strings

Voyons d'abord comment créer un string.

1a - Déclaration d'un String

On définit un String à l'aide d'un caractère séparateur signalant le début de la chaîne et on utilise le même caractère pour signaler la fin de la chaîne.

C'est un objet natif de Python, de la classe str.

Ces caractères séparateurs peuvent être :

  • Des guillemets simples ' : ils autorisent à placer des guillemets doubles " dans la chaîne.
  • Des guillemets doubles " : ils autorisent à placer des guillemets simples ' dans la chaîne.
  • Des guillements simples ou doubles en triple exemplaire """ ou ''' : on peut alors définir la chaîne sur plusieurs lignes. C'est la technique utilisée pour définir les commentaires multilignes par exemple. Cette solution permet en plus de placer des guillemets simples ou doubles dans la chaïne.

Quelques exemples :

>>> x ="Bonjour"

>>> print(type(x))

<class 'str'>

>>> x = 'Bonjour'

>>> print (x)

Bonjour

>>> y = "Bonjour"

>>> print (y)

Bonjour

>>> z = """Bonjour"""

>>> print (z)

Bonjour

>>> x ="Je peux contenir des guillemets double " !"

SyntaxError: invalid syntax

>>> x = 'Je peux contenir des guillemets double " !'

>>> print(x)

Je peux contenir des guillemets double " !

On peut transformer un autre objet en string en utilisant la fonction générale str(x) où x est l'objet que vous voulez transformer. Cette fonction str envoie un résultat qui dépend de l'objet et de la façon dont la méthode spéciale __str__ a été créée (ou non). Voir les activités sur les Classes si vous voulez en savoir plus.

>>> x = 45E-2

>>> x

0.45

>>> y = str(x)

>>> print(y)

0.45

>>> y

'0.45'

On voit bien que y est la transformation de x en string. Avec le print, on ne voit pas la différence mais si on regarde le contenu de la variable, on voit que y est entourée par des guillemets simples : c'est la façon pour Python de stocker les strings. Si on veut réellement être convaincu, il suffit enfin d'afficher le type des variables x et y :

>>> type(x)

<class 'float'>

>>> type(y)

<class 'str'>

Il est temps de voir comment lire le contenu d'un string.

1b - Objet ordonné et itérable

Un String est un ensemble ordonné de caractères : on peut y accéder en utilisant un index chiffré.

On peut accéder au contenu de l'index x en utilisant des crochets : [i].

Attention : la case du début est la case 0.

>>> x ="Bonjour"

>>> print(x[0])

B

>>> print(x[1])

o

On peut connaître la longueur d'un string en utilisant la fonction générale len(x) où x est l'objet à étudier.

>>> print(len(x))

7

On voit bien que Bonjour contient 7 caractères ( numérotés de 0 à 6, attention).

On peut alors lire le contenu du string en utilisant une boucle for associée à la longueur de la chaïne :

>>> x ="Bonjour"

>>> for i in range(len(x)):

...    print(x[i])

...

B

o

n

j

o

u

r

Ce n'est pas le moyen le plus simple de lire les caractères un par un. On peut également lire le contenu d'une chaîne en utilisant une boucle for nominative : on dit que le string est itérable.

>>> x ="Bonjour"

>>> for c in x:

...    print(c)

...

B

o

n

j

o

u

r

Attention : ici c ne contient pas le numéro de la case mais bien le contenu de la case. Nous aurions pu nommer cette variable c comme dans le cas précédent (i) mais c'est une source courante d'erreur. Ici, comme je sais que cela va contenir un caractère, j'ai choisi de la noter c.

Deux grosses remarques sur l'utilisation du print pour l'affichage et sur l'extraction de certains caractères avec l'utilsation de l'intervalle.

1c - Précision sur la fonction print

De base, lorsqu'on sort d'un print, on passe à la ligne.

>>> x ="Bonjour"

>>> for c in x:

...    print(c)

...

B

o

n

j

o

u

r

Mais on peut configurer le print à l'aide d'un paramètre end = "*" : ici, à la fin d'un print, on place une étoile sans passer à la ligne.

>>> x ="Bonjour"

>>> for c in x:

...    print(c, end="*")

...

B*o*n*j*o*u*r*

Avec end="*\n", je place une étoile et je passe à la ligne (à l'aide de l'antislash et de n, pour neuw line.

>>> x ="Bonjour"

>>> for c in x:

...    print(c, end="*\n")

...

B*

o*

n*

j*

o*

u*

r*

1d - Lecture rapide des caractères d'un string

Pour lire le contenu des cases de 0 à 9 (c'est à dire tant que case < 10), on peut écrire :

x="Bonjour les gens"

for i in range(0,10): # On peut écrire plus simplement in range(10)

    print(x[i], end="")

print()

Bonjour le

On obtient les cases de 0 à 9 ( car (0,10) veut dire de i = 0 à i < 10) : Bonjour le, c'est à dire la portion en jaune de Bonjour les gens

On peut obtenir le même effet avec les instructions suivantes :

x="Bonjour les gens"

print(x[0:10]) # On peut écrire plus simplement x[:10]

Bonjour le

Pour lire le contenu des cases de 2 à 9 (c'est à dire tant que case < 10), on peut écrire :

x="Bonjour le monde"

for i in range(2,10):

    print(x[i], end="")

print()

njour le

On obtient les cases de 2 à 9 ( car (2,10) veut dire de i = 2 à i < 10) : njour le, c'est à dire la portion en jaune de Bonjour les gens

On peut obtenir le même effet avec les instructions suivantes :

x="Bonjour le monde"

print(x[2:10])

njour le

Pour lire le contenu des cases de 2 à 9 de deux en deux, on peut écrire :

x="Bonjour le monde"

for i in range(2,10,2):

    print(x[i], end="")

print()

norl

On obtient les cases de 2 à 9 ( car (2,10,2) veut dire de i = 0 à i < 10) de 2 en 2) : norl, c'est à dire la portion en jaune de Bonjour les gens

On peut obtenir le même effet avec les instructions suivantes :

x="Bonjour le monde"

print(x[2:10:2])

norl

On peut omettre de noter certains paramètres. Il suffit de ne pas le mettre mais de placer le : suivant.

Si on ne place pas le caractère initial, l'interpréteur remplacera par 0.

Si on ne place pas le caractère final, l'interpréteur ira jusqu'au bout de la chaïne.

Si on ne place pas la valeur de l'itération, l'interpréteur augmentera de 1 en 1.

Ainsi les cas suivants sont équivalents :

>>> x = "Bonjour"

>>> print(x[0:5:1])

Bonjo

>>> print(x[0:5])

Bonjo

>>> print(x[:5])

Bonjo

Et un dernier truc pour la route : comment inverser une chaîne de caractère ? Il suffit de lui dire de compter non pas en 1 mais en -1 !.

Ici, je ne précise ni le début de la chaîne, ni la fin. J'ai donc noter :: pour indiquer que je donne uniquement la valeur de l'itération.

>>> x = "Bonjour"

>>> print(x[::-1])

ruojnoB

Pour lire un string à l'envers, on peut même faire mieux encore avec la fonction reversed() qui va renvoyer les index dans le sens inverse. C'est une fonction optimisée pour parcourir un objet itérable en sens inverse, elle sera donc normalement plus rapide que la méthode précédente qui est plus généraliste.

x="Bonjour le monde"

for c in reversed(x) :

    print(c, end="")

print()

Par contre, pour créer un nouveau string inversé, y = x[::-1] est plus adapté que de passer par la boucle.

1e - Le string est non-mutable

Cela veut dire qu'on ne peut pas modifier un string après sa création.

Première conséquence : pas de modification possible par interaction directe :

On ne peut pas modifier un string en utilisant un code de ce type :

>>> x = "Bonjour"

>>> x[2] = 'O'

TypeError: 'str' object does not support item assignment

Deuxième conséquence : toute utilisation du même nom de variable suivi du signe = crée en réalité un nouveau string.

Lorsqu'on "modifie" un string par concaténation par exemple, on crée un nouvel objet :

>>> x = "Bonjour"

>>> id(x)

2746216811016

>>> x = x + ' le monde !'

>>> id(x)

2746216863040

On voit ici clairement qu'on utilise le même nom x mais qu'on fait référence à deux entités différentes.

De la même manière, la copie d'un string ne permet pas de suivre les modifications effectuées dessus :

>>> x = "Bonjour"

>>> y = x

>>> id(x)

2746216811016

>>> id(y)

2746216811016

>>> x = x + ' le monde !'

>>> id(x)

2746216863040

>>> id(x)

2746216811016

On voit bien que x et y pointent vers le même objet au début mais que lorsqu'on modifie x, y ne suit pas.

1f - Test d'égalité de deux strings

On peut comparer deux strings de deux façons :

  • A l'aide d'un test logique x == y qui teste l'égalité de contenu.
  • A l'aide d'un test x is y qui teste l'égalité d'identité (même objet). On peut dire que is teste si x et y sont deux alias du même objet.

Si vous n'allez pas plus loin dans cette sous-partie, retenez ceci : Pour comparer le contenu de deux strings, utilisez toujours ==..

>>> x = "azerty"

>>> y = "azerty"

>>> x == y

True

L'explication est donnée au fil des exemples ci-dessous.

Quelques exemples pour comprendre la différence.

Premier exemple : x et y sont identiques (même objet, donc même contenu) :

>>> x = "azerty"

>>> y = x

>>> x == y

True

>>> x is y

True

>>> id(x)

2746216888504

>>> id(y)

2746216888504

Les deux tests donnent donc True.

Deuxième exemple : x et y sont différents en contenu et en adresse. :

>>> x = "azerty"

>>> y = "azer"

>>> x == y

False

>>> x is y

False

>>> id(x)

2746216888504

>>> id(y)

2746216888280

Pas de surprise, les deux tests donnent False.

Troisième exemple : x et y sont différents en adresse mais pas en contenu :

On reprend l'exemple précédent mais on rajoute "ty" à y :

>>> y = y + "ty"

>>> x == y

True

>>> x is y

False

>>> id(x)

2746216888504

>>> id(y)

2746216354120

On voit bien que x et contiennent tous les deux 'azerty' : le test == sur le contenu répond True.

Par contre, x et y ne pointent pas vers la même 'adresse' : ce ne sont pas des alias du même objet. Le test is renvoit donc False.

Donc, attention : pour tester l'égalité du contenu, il faut utiliser ==.

En réalité, il est même possible que Python réponde True en réponse à un is alors que vous pensiez peut-être qu'il allait répondre False.

>>> x = "abc"

>>> z = "def"

>>> y = "abc"

On voit ici que x et y ont le même contenu mais ont été créés de façon distincte : ce ne sont normalement pas les mêmes objets.

Sauf que Python tente d'optimiser l'utilisation de la mémoire : il va utiliser le même espace mémoire pour x et y car les deux opérations sont effectuées de façon assez proche l'une de l'autre.

>>> x == y

True

>>>x is y

True

>>> id(x)

2636396186960

>>> id(y)

2636396186960

Bref, je répète : le test is ne doit pas, sauf exception bien comprise, être utilisé sur les strings.

1g - Test d'appartenance

Pour savoir si un string x contient un autre string, on peut par contre utiliser le test in :

>>> x = "azerty"

>>> "a" in x

True

>>> "er" in x

True

>>> "azty" in x

False

Comme on le voit, il faut que les caractères se suivent directement. Lorsqu'on teste la présence de 'azty', on ne teste pas la présence d'un a, d'un z, d'un t et d'un y mais bien de la séquence 'azty'.

Il existe des strings constantes internes à la classe string pour ne pas à avoir à taper tous les caractères d'un type commun. C'est pratique pour faire un test avec in. Voir les méthodes : il existe même des méthodes qui vous font tout le boulot.

Pour les lettres du code ASCII :

>>> from string import ascii_letters

>>> ascii_letters

'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

>>> from string import ascii_lowercase

>>> ascii_lowercase

'abcdefghijklmnopqrstuvwxyz'

>>> from string import ascii_uppercase

>>> ascii_uppercase

'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

Pour les caractères permettant d'écrire les nombres, il existe une constante pour les chiffres en base 10, en base 16 et en base 8.

>>> from string import digits

>>> digits

'0123456789'

>>> from string import hexdigits

>>> hexdigits

'0123456789abcdefABCDEF'

>>> from string import octdigits

>>> octdigits

'01234567'

Pour tester si un caractère est un caractère de ponctuation ASCII :

>>> from string import punctuation

>>> punctuation

'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

Pour tester si un caractère est un caractère imprimable ASCII (c'est à dire par un caractère de commande (fin de fichier ...) :

>>> from string import printable

>>> printable

'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'

Pour tester si un caractère peut être considéré comme un espace ASCII :

>>> from string import whitespace

>>> whitespace

' \t\n\r\x0b\x0c'

2 - Méthodes des strings

Des exemples d'utilisation se trouvent sous le tableau.

Attention : les crochets [ ] indiquent que l'argument qu'on y touve est optionnel.

Méthode Action réalisée
str.capitalize() Renvoie une version du string où le premier caractère est en majuscule (uppercase) et les autres en minuscule (lowercase).
str.title() Renvoie une version du string où chaque mot commence par une majuscule et les autres caractères en minuscule.
str.lower() Renvoie la chaîne de caractères en remplaçant les caractères par les minuscules correspondantes.
str.upper() Idem mais en majuscule.
str.swapcase() Renvoie une chaîne en transformant les majuscules en minuscules et inversement.
str.center(largeur [,remplissage]) Renvoie une version du string faisant "largeur" caractères, le caractère de remplissage étant donné via remplissage.
str.ljust(largeur [,remplissage]) Idem mais avec une mise à gauche (d'où le l pour left).
str.rjust(largeur [,remplissage]) Idem mais avec une mise à droite (d'où le r pour right).
str.count(sub[, start[, end]]) Renvoie le nombre d'occurences du string sub dans le string str. On peut rajouter les numéros de début et de fin des cases à analyser.
str.encode(encoding=”utf-8”, errors=”strict”)] Renvoie la version encodée du string str. L'encodage par défaut est utf-8
str.endswith(suffix[, start[, end]]) Retourne False si la chaîne utilisée ne finit pas par le suffix donné. Le suffixe peut également être un tuple, la fonction regardera alors si le string finit par l'ue des valeurs du tuple. Pratique pour vérifier le type d'extension d'un fichier.
str.startswith(suffix[, start[, end]]) Pareil mais avec le début.
str.expandtabs(tabsize=8) Renvoie une copie de str dans laquelle les tabulations \t sont remplacées par des espaces.
str.find(sub[, start[, end]]) Renvoie le numéro d'index de la première occurrence du string sub dans le string str sur lequel on travaille. On peut indiquer de ne travailler que sur un bout du string à l'aide de start et end. La réponse est -1 si elle ne trouve pas sub dans str.
str.index(sub[, start[, end]]) Comme la précédente mais lève une erreur de type ValueError plutôt que -1 si elle ne trouve pas la chaîne désirée.
str.rfind(sub[, start[, end]]) Comme find mais avec la valeur la plus grande trouvée, plutôt que la première.
str.rindex(sub[, start[, end]]) Comme la précédente mais avec une erreur plutôt que -1 si on ne trouve pas.
str.format(*args, **kwargs) Permet de placer des éléments à certains endroits précise d'un string Exemple : "La somme de 1 + 2 est {0}".format(1+2) va insérer le calcul (1+2) à la place de {0}. Voir les questions ci-dessous pour plus de précision.
str.join(iterable) Intercale le string str entre chaque valeur de l'objet iteritable : ainsi "*".join("A","B","C") renvoie A*B*C. Ou "ABC".join("/*-") renvoie /ABC*ABC-ABC".
str.lstrip([chars]) Renvoie une copie de str où on a supprimé une partie du début de str : la partie qui comporte les caractères présents dans chars. Ainsi 'www.example.com'.lstrip('cmowz.') renvoie example.com. Si on ne précise rien en utilisant juste lstrip(), la méthode supprime par défaut les espaces.
str.rstrip([chars]) Comme la précédente mais en commençant par la droite, donc la fin.
str.strip([chars]) Encore plus violent : cette méthode retire les caractères données de la chaîne de caractères au début et à la fin. Exemple : "Bonjour".strip("Br") renvoie "onjou".
str.partition(sep) Renvoie un tuple 3-uplet qui contient : (la sous-chaîne avant le séparateur), (le séparateur), (la sous-chaine après le séparateur). Exemple : "AB.CDE.FGHI".partition('.') renvoie ('AB','.','CDE.FGHI').
str.rpartition(sep) Comme la précédente mais en prenant le premier séparateur trouvé en partant de la droite.
str.replace(old, new[, count]) Renvoie une copie de str où la chaîne old sera remplacée par la chaîne new. Si on précise un integer count, le remplacement ne sera fait que ce nombre de fois.
str.split(sep=None, maxsplit=-1) Renvoie un tuple contenant les sous-chaînes qu'il trouve en utilisant le caractère séparateur fourni. Exemple : "A;B;C".split(";") fournit la liste ['A', 'B', 'C']. Si on ne précise pas maxsplit, il vaut -1 par défaut et on divise autant de fois qu'il le faut.
str.rsplit(sep=None, maxsplit=-1) Comme ci-dessus mais en commençant par la droite.
str.splitlines([keepends]) Renvoie une liste contenant les différentes chaînes de caractères, le séparateur étant ici le passage à la ligne, souvent noté \n. Néanmoins, la méthode intégre d'autres caractères de séparation. Allez voir la documentation si vous voulez l'utiliser.
str.zfill(largeur) Renvoie une copie du string en rajoutant des 0 au début de façon à ce que le str ai la bonne largeur (width). Si un caractère de signe ou autre se trouve devant (+, -), il restera à l'extrême gauche.

Exemple : str.capitalize()

>>> a="azerTY"

>>> print(a.capitalize())

Azerty

Exemple : str.center(largeur [,remplissage])

>>> a="Bonjour"

>>> print(a.center(50,'-'))

---------------------Bonjour----------------------

Exemple : str.count(sub[, start[, end]])

>>> a="Bonjour"

>>> print(a.count('o'))

2

>:>> print(a.count('o',0,2))

1

Exemple : str.encode(encoding=”utf-8”, errors=”strict”)]

>>> a="Cela a fonctionné"

>>> print(a.encode())

b'Cela a fonctionn\xc3\xa9'

>:>> for octet in a.encode():

...    print(octet, end=" ; ")

67 ; 101 ; 108 ; 97 ; 32 ; 97 ; 32 ; 102 ; 111 ; 110 ; 99 ; 116 ; 105 ; 111 ; 110 ; 110 ; 195 ; 169 ;

>>> print(a.encode('ansi'))

b'Cela a fonctionn\xe9'

>>> for octet in a.encode('ansi'):

...    print(octet, end=" ; ")

67 ; 101 ; 108 ; 97 ; 32 ; 97 ; 32 ; 102 ; 111 ; 110 ; 99 ; 116 ; 105 ; 111 ; 110 ; 110 ; 233 ;

Quelques explications : le 'b' signifie qu'on a en réalité affaire à un ensemble de bytes. Par contre, lorsque la valeur du byte est inférieure à 127 (en base 10) et correspond à une lettre de l'ASCII, Python affiche la lettre ASCII correspondante plutôt que la valeur. Si le code est supérieur à 127 (base 10), il donne la façon dont la lettre est codée en hexadécimal (il indique que c'est de l'hexa à l'aide du \x placé devant la valeur).

Ainsi dans l'encodage UTF-8, é est codé sur deux octets, dont les valeurs sont exprimées par c3 a9 en hexadécimal et 195 169 en décimal.

Par contre, dans l'encodage ANSI, é est codé sur un seul octet contenant e9 en hexadécimal ou 233 en décimal.

Exemple : str.endswith(suffix[, start[, end]])

>>> a="Bonjour."

>>> print(a.endswith(';'))

False

>>> print(a.endswith('.'))

True

>>> print(a.endswith(('.',';')))

True

Exemple : str.find(sub[, start[, end]])

>>> a="Bonjour"

>>> print(a.count('o'))

2

>>> print(a.count('o',0,2))

1

Exemple : str.format(*args, **kwargs)

L'utilisation basique est celle d'un remplissage progressif des "trous" provoqués par { } :

>>> a="Bonjour {}, aujourd'hui nous sommes {}."

>>> print(a.format('jeune Skywalker','jeudi'))

Bonjour jeune Skywalker, aujourd'hui nous sommes jeudi.

Mais on peut faire mieux encore : on peut donner un ordre d'affichage : {1} veut dire d'aller chercher l'élément classé 1 dans la liste des éléments donnés. Attention, l'élément classe 0 est le premier, comme toujours.

>>> a="Bonjour {1}, aujourd'hui nous sommes {0}."

>>> print(a.format("vendredi, pouf, ça passe vite","Yoda"))

Bonjour Yoda, aujourd'hui nous sommes vendredi, pouf, ça passe vite.

Ou encore :

>>> a = "Aujourd'hui, nous sommes {3}."

>>> a.format('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche')

'Aujourd'hui, nous sommes jeudi.'

Et ce n'est que le tout sommet de l'iceberg. Il y a beaucoup trop à dire. Cela mérite une fiche à part.

A titre d'exemple :

>>> jours=('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche')

>>> a = "Bonjour, nous sommes {b[3]}."

>>> a.format(b=jours)

'Bonjour, nous sommes jeudi.'

Il reste encore toutes les méthodes qui permettent de vérifier si la chaîne possède certaines propriétés. Ces méthodes commencent toutes par is pour dire : la chaîne est-elle ainsi ... Elles renvoient toutes True ou False.

Le test est plus ou moins explicite. Si vous voulez plus d'informations, allez voir la documentation officielle.

Méthode Action réalisée
str.isalpha() Retourne True si tous les caractères sont des lettres.
str.isdecimal() Retourne True si tous les caractères sont des chiffres : 0123456789.
str.isdigit() Comme le cas précédent mais avec en plus les caractères comme ² ³ ¹ ¼ ½ ¾ et tous les autres caractères considerés comme des nombres (sigle comme ⓫, nombres romains...)
str.isnumeric() Pareil. Il faut faire un test comparatif avec le cas précédent pour voir la différence. Utiliser une boucle for x, la fonction chr et tester chr(x).isdigit().
str.isprintable() Retourne True si tous les caractères (sans exception) sont imprimables.
str.isspace() Idem mais si tous les caractères peuvent être considérés comme des espaces.
str.isupper() Idem mais si tous les caractères sont des majuscules.
str.isalphanum() .Teste en même temps :isalpha(), isdecimal(), isdigit(), et isnumeric(). Renvoie True si l'une des méthodes renvoie True.

Et voilà. Des méthodes, il y a pour beaucoup d'autres objets que les strings : vous trouverez sur Python.org des méthodes pour les integers, les floats ... S'il vous prend l'idée de faire quelque chose avec un type prédéfini, pensez à aller y jeter un oeil : il existe peut-être une méthode déjà écrite qui fait exactement ce que vous voulez.