--- jupytext: text_representation: extension: .md format_name: myst format_version: 0.13 kernelspec: display_name: C++17 language: C++17 name: xcpp17 rise: auto_select: first autolaunch: false centered: false controls: false enable_chalkboard: true height: 100% margin: 0 maxScale: 1 minScale: 1 scroll: true slideNumber: true start_slideshow_at: selected transition: none width: 90% --- +++ {"slideshow": {"slide_type": "slide"}} # Lecture et écriture dans des chaînes de caractères +++ {"slideshow": {"slide_type": "notes"}} Nous avons vu comment lire et écrire facilement des valeurs de types divers (entiers, flottants) dans un fichier texte. Sous le capot cela a requis des opérations de natures différentes : 1. interactions avec le système pour lire et écrire du texte dans un fichier 2. conversions de valeurs en texte et réciproquement Ne pourrait-on pas utiliser ce deuxième point pour lire et écrire des valeurs dans des chaînes de caractères? Après tout, elles contiennent du texte elles aussi! Allons-y. +++ {"slideshow": {"slide_type": "fragment"}} Au préalable, nous aurons besoin de la bibliothèque suivante : ```{code-cell} --- slideshow: slide_type: fragment --- #include <sstream> using namespace std; ``` +++ {"slideshow": {"slide_type": "slide"}} ## Lecture depuis une chaîne de caractères +++ {"slideshow": {"slide_type": "fragment"}} ### Exemple +++ {"slideshow": {"slide_type": "fragment"}} La chaîne de caractère suivante contient -- sous forme de texte -- plusieurs nombres : ```{code-cell} --- slideshow: slide_type: fragment --- string s = "1 2 4 8 16"; ``` Comment extraire ces nombres de `s`? +++ {"slideshow": {"slide_type": "notes"}} On souhaiterait extraire ces nombres en les convertissant en entiers. Pour cela on créé un *flux* de type `istringstream` (pour flux entrant depuis une chaîne de caractères) rattaché à `s` : ```{code-cell} --- slideshow: slide_type: fragment --- istringstream flux = istringstream(s) ``` +++ {"slideshow": {"slide_type": "fragment"}} Maintenant il est possible de lire le premier nombre, en procédant comme s'il était dans un fichier : ```{code-cell} --- slideshow: slide_type: fragment --- int i; ``` ```{code-cell} --- slideshow: slide_type: fragment --- flux >> i; i ``` +++ {"slideshow": {"slide_type": "fragment"}} Lorsque l'on effectue de nouvelles lectures, les nombres suivants sont lus un à un : ```{code-cell} --- slideshow: slide_type: fragment --- flux >> i; i ``` ```{code-cell} --- slideshow: slide_type: fragment --- flux >> i; i ``` ```{code-cell} --- slideshow: slide_type: fragment --- flux >> i; i ``` +++ {"slideshow": {"slide_type": "slide"}} L'exemple suivant illustre que l'on peut lire successivement des valeurs de types mixtes, qu'un nombre quelconque d'espaces sert de séparateur, et que l'on peut enchaîner ces lectures : ```{code-cell} --- slideshow: slide_type: fragment --- string s = "truc 33 bidule 2.5 reste" ``` ```{code-cell} --- slideshow: slide_type: fragment --- istringstream flux = istringstream(s); ``` ```{code-cell} --- slideshow: slide_type: fragment --- string a, b; int i; float f; ``` ```{code-cell} --- slideshow: slide_type: fragment --- flux >> a >> i >> b >> f; ``` ```{code-cell} --- slideshow: slide_type: fragment --- a ``` ```{code-cell} --- slideshow: slide_type: fragment --- b ``` ```{code-cell} --- slideshow: slide_type: fragment --- i ``` ```{code-cell} --- slideshow: slide_type: fragment --- f ``` +++ {"slideshow": {"slide_type": "slide"}} ### Syntaxe et sémantique +++ {"slideshow": {"slide_type": "fragment"}} :::{admonition} Syntaxe ```c++ istringstream flux = istringstream(s); flux >> variable1; flux >> variable2; ... ``` ::: +++ {"slideshow": {"slide_type": "fragment"}} :::{admonition} Sémantique Affecte aux variables `variable1`, `variable2`, ... les valeurs lues successivement depuis la chaîne de caractères `s`, en tenant compte de leurs types respectifs. ::: +++ {"slideshow": {"slide_type": "slide"}} ## Écriture dans une chaîne de caractères Réciproquement, on peut souhaiter écrire le contenu de variables non pas directement à l'écran ou dans un fichier mais dans une chaîne de caractères. Le principe sera le même que pour une lecture. +++ {"slideshow": {"slide_type": "fragment"}} ### Exemple +++ {"slideshow": {"slide_type": "fragment"}} On commence par définir un flux de type `ostringstream` (pour flux sortant vers une chaîne de caractères) : ```{code-cell} --- slideshow: slide_type: fragment --- ostringstream flux; ``` +++ {"slideshow": {"slide_type": "fragment"}} Nous pouvons maintenant écrire dans ce flux : ```{code-cell} --- slideshow: slide_type: fragment --- flux << 3.53 << " coucou " << 1 << endl; flux << 42 << endl; ``` +++ {"slideshow": {"slide_type": "fragment"}} et enfin extraire la chaîne de caractère produite : ```{code-cell} --- slideshow: slide_type: fragment --- string s = flux.str(); s ``` +++ {"slideshow": {"slide_type": "slide"}} ### Syntaxe et sémantique +++ {"slideshow": {"slide_type": "fragment"}} :::{admonition} Syntaxe ```c++ ostringstream flux; flux << variable1; flux << variable2; string s = flux.str() ``` ::: +++ {"slideshow": {"slide_type": "fragment"}} :::{admonition} Sémantique Construit une chaîne de caractères `s` en écrivant successivement le contenu des variables `variable1`, `variable2`, ... en tenant compte de leurs types respectifs. ::: +++ {"slideshow": {"slide_type": "slide"}} ## Application typique : séparation calcul et entrées sorties +++ {"slideshow": {"slide_type": "notes"}} Ce que nous venons de voir sera très utile pour séparer proprement ce qui relève du **calcul** et ce qui relève des **entrées-sorties**. Supposons par exemple que nous souhaitions afficher joliment une entrée d'un annuaire : ```{code-cell} --- slideshow: slide_type: fragment --- using namespace std; #include <iostream> #include <sstream> ``` ```{code-cell} --- slideshow: slide_type: fragment --- void afficheEntreeAnnuaire(string nom, string prenom, string tel) { cout << "Nom: " << nom << ", Prénom: " << prenom << ", Téléphone: " << tel; } ``` ```{code-cell} --- slideshow: slide_type: fragment --- afficheEntreeAnnuaire("Lovelace", "Ada", "07 23 23 23 23") ``` +++ {"slideshow": {"slide_type": "fragment"}} :::{admonition} Questions - Comment réutiliser cette fonction pour écrire le texte non pas à l'écran mais dans un fichier? - Comment tester cette fonction? ::: +++ {"slideshow": {"slide_type": "fragment"}} Cela est rendu difficile par le mélange de deux actions de natures différentes dans une seule fonction : 1. Construire le texte représentant l'entrée dans l'annuaire. 2. Afficher ce texte à l'écran. +++ {"slideshow": {"slide_type": "fragment"}} Il faut donc **séparer** ces deux actions. L'écriture dans une chaîne va nous aider à le faire. +++ {"slideshow": {"slide_type": "fragment"}} La fonction suivante se concentre sur la construction du texte représentant l'entrée dans l'annuaire : ```{code-cell} --- slideshow: slide_type: fragment --- string formateEntreeAnnuaire(string nom, string prenom, string tel) { ostringstream flux; flux << "Nom: " << nom << ", Prénom: " << prenom << ", Téléphone: " << tel; return flux.str(); } ``` +++ {"slideshow": {"slide_type": "fragment"}} Le texte produit est **renvoyé** par la fonction au lieu d'être **affiché**. Nous pouvons donc maintenant : - l'affecter à une variable : ```{code-cell} --- slideshow: slide_type: fragment --- string s = formateEntreeAnnuaire("Lovelace", "Ada", "07 23 23 23 23") ``` +++ {"slideshow": {"slide_type": "fragment"}} - l'afficher : ```{code-cell} --- slideshow: slide_type: fragment --- cout << s << endl; ``` +++ {"slideshow": {"slide_type": "fragment"}} - calculer avec : ```{code-cell} --- slideshow: slide_type: fragment --- "- " + s ``` +++ {"slideshow": {"slide_type": "fragment"}} - ou nous en servir pour toute autre opération, comme l'écrire dans un fichier. +++ {"slideshow": {"slide_type": "fragment"}} De plus, nous pouvons maintenant aisément tester notre fonction : ```{code-cell} --- slideshow: slide_type: fragment --- CHECK( formateEntreeAnnuaire("Lovelace", "Ada", "07 23 23 23 23") == "Nom: Lovelace, Prénom: Ada, Téléphone: 07 23 23 23 23" ); ``` +++ {"slideshow": {"slide_type": "slide"}} ## Résumé Dans cette feuille: - nous avons vu comment **lire et écrire** des données de types divers **dans des chaînes de caractères**. - Nous l'avons appliqué pour mieux séparer **fonctions qui calculent** et **fonctions d'entrées-sorties**. - Enfin nous avons noté que, grâce au concept de flux, on peut utiliser la même syntaxe que pour lire et écrire dans un fichier ou pour interagir avec l'utilisateur.