String et stream ✱
Bien que beaucoup d’efforts aient été faits pour améliorer le support des caractères internationaux en C++, cela reste encore fastidieux. Nous choisissons donc dans cette unité de se limiter aux caractères de la table ASCII de 32 à 126, c’est à dire :
Les chiffres et les lettres majuscules/minuscules
L’espace
Les signes de ponctuation : ! ? . ; ,
Les signes mathématiques : + - / * % < > =
Les signes de dev : ( ) [ ] {} & # " ~
Et quelques autres : $ _ - @ ^
Avertissement
Par exemple, vous ne pouvez donc pas utiliser les accents : é à è ê et le ç. En effet, ces caractères nécessitent un encodage sur 2 octets ou plus. Ainsi, si vous demandez la longueur de la chaîne, la fonction retournera en réalité le nombre d’octets utilisés et ce résultat ne correspondra pas aux nombres de caractères effectivement présents dans la chaîne.
Les littéraux
Dans vos programmes vous allez écrire des littéraux sous la forme suivante :
"Bonjour"
Cette syntaxe, datant du langage C, correspond à la création d’un tableau de caractères char[]. Il est possible d’y insérer des caractères spéciaux en utilisant un backslash \ :
\n : retour à la ligne
\t : tabulation
\\ : un backslash (pour les chemins sur le disque)
Le type string
La librairie standard du C++ (std) intègre le type string pour représenter des objets chaînes de caractères. Pour cela, il faut insérer en début de votre code la ligne suivante :
#include <string>
Pourquoi le langage fournit un objet string alors que les chaînes de caractères datant du C semblent largement suffire :
Un objet string peut changer de taille dynamiquement en insérant ou retirant des caractères. Les tableaux de char sont de taille fixe.
Les chemins de fichier ne sont plus limités en taille ! Sans utiliser un string, on doit alors allouer un tableau de taille fixe pour stocker un chemin de fichier, une belle source de bugs !
De nombreuses fonctions sont disponibles à travers l’objet string ce qui facilite l’écriture et la relecture du code.
On peut utiliser des opérateurs sur les string comme le + pour fusionner deux chaînes.
Syntaxe
Le classe string est une spécialisation de la classe modèle std::basic_string<T> pour le type char. On peut trouver toutes les spécifications de cette classe modèle sur cette page. Voici une liste des commandes intéressantes :
Type |
Exemple |
|
---|---|---|
Affichage |
std::cout << s1 << std::endl; |
|
Initialisation |
std::string s1 = "Exemple 1"; |
|
Initialisation |
std::string s2("Exemple 2"); |
|
Initialisation |
std::string t {"Hello world"}; |
|
Conversion int->str |
std::string s = std::to_string(42); |
|
Conversion str->int |
std::stoi(s); |
|
Conversion str->double |
std::stod(s); |
|
Conversion str->float |
std::stof(s); |
|
Méthode |
t.clear() |
Efface tous les caractères |
Méthode |
t.erase(i٬nb) |
Retire nb caractères à partir de l’index i |
Méthode |
t.insert(i٬"1-") |
Insère une chaîne dans la chaîne t à la position i |
Méthode |
t.erase(index٬nb) |
Retire nb caractères à la position i |
Méthode |
t.replace(index٬nb٬"test") |
Remplace les nb caractères à la position i |
Méthode |
t.append(s1) |
Insère en fin |
Méthode const |
t.length() |
Nombre de caractères |
Méthode const |
t.find("Ex") |
Retourne l’index de la première occurrence |
Méthode const |
t.rfind("Ex") |
Retourne l’index de la dernière occurrence |
Méthode const |
t.substr(i٬nb) |
Retourne une sous-chaîne depuis l’index i |
Opérateur + |
s1+"@"+s2 |
Concaténation |
Opérateur += |
s1+= "fin" |
Insère en fin |
Opérateur [] |
s1[i] |
retour le i-ème caractère |
Opérateur < |
s1 < s2 |
Comparaison lexicographique |
Opérateur == |
s1 == s2 |
Comparaison des caractères |
Test |
t.empty() |
Indique si la chaîne est vide |
Test |
t.starts_with("Ex") |
Teste le début de la chaîne de caractères |
Test |
t.ends_with("1") |
Teste la fin de la chaîne de caractères |
Indiquez si les affirmations suivantes sont vraies ou fausses :
L’écriture "3" correspond à un littéral.
Pour créer un string, une seule syntaxe est possible.
Le type string est un type fondamental du C++.
On peut concaténer un string avec un int.
L’écriture : string s = 42 convertit implicitement un int en string.
La fonction stod() convertit un double en string.
La fonction to_string() permet de convertir un numérique en string.
Les variables s1 et s2 représentent deux string initialisés avec "BOB" et "EVA". Pour chacune des expressions, donnez le résultat SANS guillemets s’il existe ou indiquez ERR :
Expression |
Résultat |
---|---|
"Hello" + 4 |
|
s1 + "_" + s2 |
|
s1 + 5 |
|
to_string(50) |
Affichage
iostream
Cette librairie propose un objet cout permettant d’effectuer des sorties sur la console de manière plus intuitive que la fonction printf. Pour cela, l’opérateur << a été redéfini pour traiter tous les types fondamentaux. Pour les booléens cependant, il affiche 0 pour false et 1 pour true.
La librairie <iostream> inclut aussi des constantes comme endl pour effectuer un retour à la ligne. Nous pouvons ainsi écrire :
#include <iostream>
int main()
{
int a = 17;
string t = "Bonjour";
std::cout << a << std::endl << t << std::endl;
}
Note
Vous pouvez retirer les std en écrivant : using namespace std;
En chaînant plusieurs affichages à la suite, les éléments sont accolés, ainsi cout << 18 << 13 affiche 1813. Il faut alors penser à insérer des espacements supplémentaires pour rendre l’affichage lisible :
cout << "Coordonnées : " << x << " " << y << endl;
Formatage des nombres
La librairie <iomanip> fournit une fonction setprecision() permettant de contrôler l’affichage des nombres flottants :
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << setprecision(5) << 3.141519 << endl; // ==>> 3.1415 5 chiffres
cout << setprecision(3) << 3.141519 << endl; // ==>> 3.14 3 chiffres
cout << setfill('-');
cout << setw(5) << 25 << endl; // ---25
cout << setw(5) << 148; // --148
}
Surcharger l’opérateur << pour vos objets
Pour les structures, on peut surcharger l’opérateur << pour qu’il sache afficher vos objets. Ainsi, vous fixez un format d’affichage identique pour tous les objets de même type. Voici un exemple dans le code ci-dessous :
#include <iostream>
using namespace std;
struct Point
{
int x,y;
Point(int xx,int yy) { x = xx; y = yy; }
};
ostream & operator << (ostream & stream, const Point & P)
{
stream << "(" << P.x << "," << P.y << ")";
return stream;
}
int main()
{
Point P(4,5);
cout << P;
}
>> (4,5)
Stream
Rappel : le polymorphisme permet à des objets d’une même hiérarchie de classes de partager une interface identique. Ainsi, bien que les instances soient de natures différentes, elles vont se comporter de manière similaire.
Output stream
Dans la hiérarchie des output streams, on trouve :
std::cout : instance de la classe mère ostream (output stream)
ostringstream : classe fille dédiée aux sorties dans une chaîne de caractères (output string stream)
ofstream : classe fille dédiée aux sorties dans un fichier (output file stream)
Exemple
Nous avons vu les fonctionnalités disponibles à travers l’objet cout pour l’affichage à l’écran. Ainsi, toutes les instances appartenant à la même hiérarchie disposent des même facilités !
#include <iostream>
#include <sstream>
#include <fstream>
void ExPolymorphisme(std::ostream & s, int i)
{
s << "File_" << i << ".txt" << std::endl;
}
int main()
{
// sortie à l'écran
ExPolymorphisme(std::cout,7);
// sortie dans un string buffer
std::ostringstream os;
ExPolymorphisme(os, 7);
std::cout << os.str();
// sortie dans un fichier
std::ofstream ofs("C:\\test\\output.txt");
ExPolymorphisme(ofs, 7);
ofs.close();
return 0;
}
>> Affichage : File_7.txt
>> String : File_7.txt
Input stream
La logique est identique pour les inputs streams ; une classe mère istream dipose d’une instance std::cin ainsi que deux classes filles :
ifstream spécialisée dans la lecture des fichiers (input file stream)
istringstream spécialisée dans la lecture des chaînes de caractères (input string stream)
Voici un programme d’exemple gérant les trois types d’entrée :
Le clavier avec std::cin, l’utilisateur va entrer : 11 22 33 + Enter
Un objet inputstream initialisé avec la chaîne : "11 22 33"
Un fichier dont le contenu est affiché ci-dessous
#include <iostream>
#include <sstream>
#include <fstream>
void ExPolymorphisme(std::istream & is)
{
int i;
is >> i;
std::cout << "word : " << i << std::endl;
}
int main()
{
// lecture au clavier
ExPolymorphisme(std::cin);
// lecture dans une chaîne
std::istringstream iss("11 12 13");
ExPolymorphisme(iss);
// lecture dans un fichier
std::ifstream ifs("C:\\test\\output.txt");
ExPolymorphisme(ifs);
ifs.close();
return 0;
}
Dans les trois cas, l’opérateur >> lit le premier nombre disponible sur le flux d’entrée c’est à dire le 11.
Note
Le caractère espace sert de séparateur entre les différentes informations.
Avertissement
Tout n’est pas aussi rose côté polymorphisme. En effet, si dans cet exemple tout fonctionne à merveille, il reste des zones d’ombre difficilement homogénéisables. Par exemple, lorsqu’il s’agit de détecter la fin du flux, pour un fichier, cette notion est évidente, mais pour l’entrée clavier… il n’y a pas de notion de fin ! Il faudra donc gérer ce genre de détails au cas par cas.
Dans les fonctions utiles, on peut citer :
std::getline(streamin,str) : lit une ligne et la charge dans l’objet string str
std::getline(streamin,str, "#") : idem mais en utilisant le caractère # comme séparateur