Décomposer une chaîne en atomes : comment parcourir les mots en C++ (sans se prendre la tête)
Imaginez : vous écrivez un analyseur de logs, un parseur de commandes ou vous voulez simplement compter les mots dans une phrase. La première chose qui vient à l'esprit est de prendre une chaîne et de parcourir chaque mot individuellement. En Python, cela se fait en une ligne : "hello world".split(). Mais nous sommes en C++, et donc la simplicité est un luxe qui se mérite.
La question "How do I iterate over the words of a string?" sur Stack Overflow a rassemblé des centaines de milliers de vues. Et ce n'est pas un hasard : les débutants se noient dans les subtilités de la gestion de la mémoire, tandis que les pros cherchent un équilibre entre vitesse et lisibilité. Dans cet article, nous allons analyser 5 méthodes d'itération sur les mots en C++, comparer leurs performances et comprendre quand utiliser laquelle.
Si vous avez déjà écrit strtok et obtenu un segfault, ou essayé d'insérer std::regex dans une boucle critique — cet article est pour vous.
Méthode n°1 : La classique — std::istringstream
La méthode la plus sûre et intuitive pour les débutants. std::istringstream fonctionne comme un flux : vous lisez simplement les mots séparés par des espaces.
#include <iostream>#include <sstream>#include <string>#include <vector>
int main() { std::string text = "C++ is not for the faint of heart"; std::istringstream stream(text); std::string word; std::vector<std::string> words; while (stream >> word) { words.push_back(word); std::cout << "Word: " << word << std::endl; } std::cout << "Total words: " << words.size() << std::endl; return 0;}Avantages : code propre, pas de pointeurs bruts, gestion automatique de la mémoire. Fonctionne avec tous les séparateurs d'espacement (tabulation, saut de ligne).
Inconvénients : plus lent que les méthodes manuelles à cause de la création du flux. Ne convient pas pour les séparateurs personnalisés (uniquement les caractères d'espacement).
Quand l'utiliser : quand la lisibilité est plus importante que la vitesse. Idéal pour les exemples pédagogiques et les prototypes.
Méthode n°2 : Rapide et dangereuse — std::strtok
Un héritage du C qui vit encore en production. strtok modifie la chaîne d'origine (insère des caractères nuls) et utilise un tampon statique.
#include <iostream>#include <cstring>#include <vector>
int main() { char text[] = "Fast but dangerous — handle with care"; std::vector<char*> words; char* token = std::strtok(text, " "); while (token != nullptr) { words.push_back(token); std::cout << "Word: " << token << std::endl; token = std::strtok(nullptr, " "); } std::cout << "Total words: " << words.size() << std::endl; return 0;}Avantages : très rapide (fonctionne au niveau des chaînes C). Permet de définir n'importe quel ensemble de séparateurs.
Inconvénients : non thread-safe, détruit la chaîne d'origine, fonctionne uniquement avec char*, pas avec std::string. Facile d'obtenir un comportement indéfini.
Quand l'utiliser : uniquement dans les boucles critiques où chaque nanoseconde compte, et que vous êtes sûr d'être en monothread. En C++ moderne, il est préférable de l'éviter.
Méthode n°3 : Parcours manuel — std::string::find et substr
Parfois, vous avez besoin d'un contrôle total. Le parcours manuel offre de la flexibilité et ne nécessite pas de bibliothèques supplémentaires.
#include <iostream>#include <string>#include <vector>
std::vector<std::string> splitManual(const std::string& text, char delimiter = ' ') { std::vector<std::string> tokens; size_t start = 0; size_t end = text.find(delimiter);