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

>>> print(x)

Bonjour

>>> x

'Bonjour'

>>> 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 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, 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  i  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 native len(x) avec len(x)x est l'objet à étudier.

>>> x = "Bonjour"

>>> 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 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 : on dit que le string est itérable.

>>> 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. Nous aurions pu nommer cette variable element comme dans le cas précédent (index) mais ce serait une source courante de confusion. Ici, comme je sais que cela va contenir un caractère, on pourrait par contre choisir de la noter caractere.

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

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

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

x = "Bonjour les gens"

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

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

print()

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]

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 :

x = "Bonjour les gens"

for index in range(2,10) :

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

print()

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

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 :

x = "Bonjour les gens"

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

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

print()

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

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"

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

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

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 objet au début mais que lorsqu'on modifie  x ,  y  ne subit pas la modification.

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 et ont 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 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 ... 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.

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 ici que l'argument qu'on y touve est optionnel.

Codification de la 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"

>>> print( 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"

>>> print( 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'occurences du string sub dans le string monString. On peut rajouter les numéros de début et de fin des cases à analyser.

>>> a = "Bonjour"

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

2

>:>> print( 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é"

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

monString.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 monString finit par l'ue des valeurs du tuple. Pratique pour vérifier le type d'extension d'un fichier.

>>> a = "Bonjour."

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

False

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

True

>>> print( 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 et end. La réponse est -1 si elle ne trouve pas sub dans monString.

>>> a = "Bonjour"

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

1

>>> print( a.find ('o',2) )

4

>>> print( 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) 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 : la partie qui comporte les caractères présents dans 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.

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

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

>>> 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 d'index 1 dans la liste des éléments donnés. Attention, l'élément d'index 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, et ça devient intéressant :

>>> 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
monString.isalpha() Retourne True si tous les caractères sont des lettres.
monString.isdecimal() Retourne True si tous les caractères sont des chiffres : 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. 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().
monString.isprintable() Retourne True si tous les caractères (sans exception) sont imprimables.
monString.isspace() Idem mais si tous les caractères peuvent être considérés comme des espaces.
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.

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.