python strings

Identification

Infoforall

Fiche Strings avec Python


L'objet str de Python est un objet :

  • itérable : on peut y accéder avec une boucle for nominative
  • ordonné : les élément sont indexés par un numéro (on peut donc utiliser un for numérique)
  • non mutable : en français, on dira non modifiable après création ou non muable (instanciation).

Cette fiche détaille l'utilisation des strings.

1 - Déclaration

Le string est un objet natif de Python, de la classe str.

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.

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 dans les docstrings par exemple. Cette solution permet en plus de placer des guillemets simples ou doubles dans la chaïne.

Quelques exemples :

>>> x = "Bonjour" >>> type(x) <class 'str'> >>> print(x) Bonjour >>> x 'Bonjour'
>>> x = 'Bonjour' >>> x 'Bonjour' >>> y = "Bonjour" >>> y 'Bonjour' >>> z = """Bonjour""" >>> 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 native str sous la forme str(x)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 de la transformation des données, il suffit enfin d'afficher le type des variables x et y :

>>> type(x) <class 'float'> >>> type(y) <class 'str'>

2 - 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  i  en utilisant des crochets :  [ i ] .

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

>>> x = "Bonjour"

>>> x[0]

'B'

>>> x[1]

'o'

La correspondance index - caractère donne ceci sur l'exemple

Index 0 1 2 3 4 5 6
'Bonjour' 'B' 'o' 'n' 'j' 'o' 'u' 'r'

On peut connaître la longueur d'un string en utilisant la fonction native len(x) avec len(x)x est l'objet à étudier.

>>> x = "Bonjour" >>> 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 numérique associée à la longueur de la chaîne  :

>>> x = "Bonjour" >>> for index in range(len(x)): ... print( x[index] ) ... 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. ATTENTION : on perd néanmoins l'information sur le numéro d'index. En fonction de ce qu'on veut faire, on prend l'une ou l'autre des méthodes.

>>> x = "Bonjour" >>> for element in x: ... print( element ) ... B o n j o u r

Attention : ici element ne contient pas le numéro de la case mais bien le contenu de la case. Ici, comme je sais que cela va contenir un caractère, on pourrait par contre choisir de la noter caractere.

>>> x = "Bonjour" >>> for caractere in x: ... print( caractere ) ... B o n j o u r

3 - Précision sur print

Souvenez-vous que le print n'est pas nécessaire dans la console : lorsque l'instruction tapée ne contient qu'un contenu, la console vous affiche le contenu demandé. Par contre, la fonction print permet de choisir la façon dont on gère l'affichage par exemple.

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

>>> x = "Bonjour" >>> for element in x : ... print( element ) ... 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 element in x : ... print( element, 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 element in x : ... print( element, end="*\n" ) ... B* o* n* j* o* u* r*

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

Cette partie explique l'utilisation de la boucle for numérique ou des slices pour lire des bouts de string. L'utilisation de slice est pratique mais ne figure pas au programme de 1er NSI. Vous ne pourrez donc pas avoir de questions les concernant à l'examen ou même des bouts de code les utilisant. On préfère vous faire manipuler les strings en utilisant simplement les boucles bornées (for). Par contre, c'est pratique et rapide. En projet, vous pouvez faire comme vous voulez.

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

1 2 3 4 5 6
x = "Bonjour les gens" for index in range(0, 10): # On peut écrire plus simplement in range(10) print( x[index], end="" ) print() # Rajout du passage à la ligne

On notera donc que si le premier numéro du range est 0, on peut l'omettre. L'interpréteur remplira avec un 0 par défaut.

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

1 2
x = "Bonjour les gens" print( x[0:10] ) # On peut écrire plus simplement x[:10]

On obtient les cases de 0 à 9 ( car (0,10) veut dire de commencer à la case 0 et de s'arrêter avant la case 10) :

  • Bonjour le      , c'est à dire la portion en jaune de :
  • Bonjour les gens.

Bonjour le

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

1 2 3 4 5 6
x = "Bonjour les gens" for index in range(2, 10): print( x[index], end="" ) print() # Rajout du passage à la ligne

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

1 2
x = "Bonjour les gens" print( x[2:10] )

On obtient les cases de 2 à 9 ( car (2,10) veut dire de commencer à la case 2 et de s'arrêter avant la case 10) 

  •   njour le      , c'est à dire la portion en jaune de :
  • Bonjour les gens.
njour le

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

1 2 3 4 5 6
x = "Bonjour les gens" for index in range(2, 10, 2): print( x[index], end="" ) print() # Rajout du passage à la ligne

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

1 2
x = "Bonjour les gens" print( x[2:10:2] )

On obtient les cases de 2, 4, 6 et 8 ( car (2,10,2) veut dire de commencer à la case 2 , de s'arrêter avant la case 10 et d'augmenter de deux à chaque fois).

  •   n o r l       , c'est à dire la portion en jaune de :
  • Bonjour les gens, c'est à dire la portion en jaune de :
  • .
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 défaut par 0.
  • Si on ne place pas le caractère final, l'interpréteur ira jusqu'au bout du string.
  • Si on ne place pas la valeur de l'itération, l'interpréteur augmentera de 1 en 1 par défaut.

Ainsi les cas suivants sont équivalents :

>>> x = "Bonjour" >>> x[0:5:1] 'Bonjo' >>> x[0:5] 'Bonjo' >>> x[:5] 'Bonjo'

Cela veut donc dire de ne garder que les caractères ayant un index strictement inférieur à 5.

Si on place le : à la fin, cela veut dire de ne garder que les caractères à partir de l'index 5 inclus.

>>> x = "Bonjour" >>> x[5:] 'ur'

Et un dernier truc pour la route : comment inverser une chaîne de caractères ? 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" >>> x[::-1] 'ruojnoB'

Pour lire un string à l'envers, on peut même faire mieux encore avec la fonction native 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.

1 2 3 4
x = "Bonjour les gens" for caractere in reversed(x): print( caractere, end="" ) print()

Par contre, pour créer un nouveau string inversé, stringInverse = stringDeBase[::-1] est plus court à taper que de taper une boucle contenant une concaténation.

5 - 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 d'une nouvelle affectation (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 donc en réalité référence à un autre identifiant.

>>> x = "Bonjour" >>> id(x) 016 >>> x = x + ' le monde !' >>> id(x) 040

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) 016 >>> id(y) 016 >>> x = x + ' le monde !' >>> id(x) 040 >>> id(x) 016

On voit bien que x et y pointent vers le même identifiant-mémoire au début mais que lorsqu'on modifie x, y ne subit pas la modification.

6 - 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 contenu mémoire et et ont donc le même id.

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 >>> x is y False

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) 504 >>> id(y) 504

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) 504 >>> id(y) 280

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 :

>>> x = "azerty" >>> y = "azer" >>> y = y + "ty" >>> x == y True >>> x is y False >>> id(x) 504 >>> id(y) 120

On voit bien que x et y 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 renvoie donc False.

Test d'égalité avec les strings en Python

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 ... 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 et qu'elles engendrent un contenu non mutable similaire.

>>> x == y True >>> x is y True >>> id(x) 960 >>> id(y) 960

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

7 - 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'

8 - Méthodes

Des exemples d'utilisation se trouvent sous le tableau.

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

Méthode Action réalisée
monString.capitalize() Renvoie une version du string monString où le premier caractère est en majuscule (uppercase) et les autres en minuscule (lowercase).
>>> a = "azerTY" >>> a.capitalize() 'Azerty'
monString.title() Renvoie une version du string monString où chaque mot commence par une majuscule et les autres caractères en minuscule.
monString.lower() Renvoie la chaîne de caractères en remplaçant les caractères par les minuscules correspondantes.
monString.upper() Idem mais en majuscule.
monString.swapcase() Renvoie une chaîne en transformant les majuscules en minuscules et inversement.
monString.center(largeur [,remplissage]) Renvoie une version du string monString faisant "largeur" caractères, le caractère de remplissage étant donné via remplissage.
>>> a = "Bonjour" >>> a.center(50, '-') ---------------------Bonjour----------------------
monString.ljust(largeur [,remplissage]) Idem mais avec une mise à gauche (d'où le l pour left).
monString.rjust(largeur [,remplissage]) Idem mais avec une mise à droite (d'où le r pour right).
monString.count(sub[, start[, end]]) Renvoie le nombre d'occurrences du string sub dans le string monString. On peut rajouter les numéros de début et de fin des cases à analyser.
>>> a = "Bonjour" >>> a.count('o') 2 >:>> a.count('o',0,2) 1
monString.encode(encoding="utf-8", errors="strict")] Renvoie la version encodée du string monString. L'encodage par défaut est utf-8
>>> a = "Cela a fonctionné" >>> 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 >>> 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.

monString.endswith(suffix[, start[, end]]) renvoie False si la chaîne utilisée ne finit pas par le suffixe donné. Le suffixe peut également être un tuple, la fonction regardera alors si le string monString finit par l'une des valeurs du tuple. Pratique pour vérifier le type d'extension d'un fichier.
>>> a = "Bonjour." >>> a.endswith(';') False >>> a.endswith('.') True >>> a.endswith(',') False
monString.startswith(suffix[, start[, end]]) Pareil mais avec le début.
monString.expandtabs(tabsize=8) Renvoie une copie de monString dans laquelle les tabulations \t sont remplacées par des espaces.
monString.find(sub[, start[, end]]) Renvoie le numéro d'index de la première occurrence du string sub dans le string monString sur lequel on travaille. On peut indiquer de ne travailler que sur un bout du string à l'aide de start (2e paramètre) et end (3e paramètre). La réponse est -1 si elle ne trouve pas sub dans monString.
>>> a = "Bonjour" >>> a.find('o') 1 >>> a.find('o',2) 4 >>> a.find('o',2,3) -1
monString.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.
monString.rfind(sub[, start[, end]]) Comme find mais avec la valeur la plus grande trouvée, plutôt que la première.
monString.rindex(sub[, start[, end]]) Comme la précédente mais avec une erreur plutôt que -1 si on ne trouve pas.
monString.format(*args, **kwargs) Remplacée maintenant par le f-string. Permet de placer des éléments à la place des accolades dans un string. Exemple :
>>> "La somme de 1 + 2 est {0}".format(1+2) 'La somme de 1 + 2 est 3'

Voir les exemples SOUS LE TABLEAU.

monString.join(iterable) Intercale le string monString entre chaque valeur de l'objet iteritable.
>>> "*".join("A","B","C") 'A*B*C' >>> "-A-".join("123) '1-A-2-A-3-A-'
monString.lstrip([chars]) Renvoie une copie de monString où on a supprimé une partie du début de monString : on supprime les caractères jusqu'à en trouver un qui n'appartient pas à chars. Si on ne précise rien en utilisant juste lstrip(), la méthode supprime par défaut les espaces.
>>> 'www.example.com'.lstrip('cmowz.') 'example.com'
monString.rstrip([chars]) Comme la précédente mais en commençant par la droite, donc la fin.
monString.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.
>>> "*-*Bonjour*-*".strip("*-") 'Bonjour'
monString.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). Cette méthode est très pratique pour obtenir l'extension d'un fichier. Exemple :
>>> "AB.CDE.FGHI".partition('.') ('AB','.','CDE.FGHI') >>> "image_42.jpg".partition('.') ('image_42','.','jpg')
monString.rpartition(sep) Comme la précédente mais en prenant le premier séparateur trouvé en partant de la droite.
monString.replace(old, new[, count]) Renvoie une copie de monString 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 maximum.
monString.split(sep=None, maxsplit=-1) Renvoie une liste contenant les sous-chaînes qu'il trouve en utilisant le caractère séparateur fourni. Si on ne précise pas maxsplit, il vaut -1 par défaut et on divise autant de fois qu'il le faut. Exemple :
>>> "A;B;C".split(";") ['A', 'B', 'C']
monString.rsplit(sep=None, maxsplit=-1) Comme ci-dessus mais en commençant par la droite.
monString.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.
monString.zfill(largeur) Renvoie une copie du string en rajoutant des 0 au début de façon à ce que le monString ai la bonne largeur (width). Si un caractère de signe ou autre se trouve devant (+, -), il restera à l'extrême gauche.

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 retournent 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
monString.isalpha() renvoie True si tous les caractères sont des lettres.
monString.isdecimal() renvoie True si tous les caractères sont des chiffres décimaux: 0123456789.
monString.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...)
monString.isnumeric() Pareil.
monString.isprintable() renvoie True si tous les caractères (sans exception) sont imprimables (voir la fiche ou l'activité sur l'encodage des caractères).
monString.isspace() Si tous les caractères peuvent être considérés comme des espaces, elle renvoie True.
monString.isupper() Idem mais si tous les caractères sont des majuscules.
monString.isalphanum() .Teste en même temps : isalpha, isdecimal, isdigit, et isnumeric. Renvoie True si l'une des méthodes renvoie True.

9 - f-strings

A faire.

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.

Article publié le 10 11 2019
Dernière modification : 10 11 2019
Auteur : ows. h.