Как разбить строку на токены (слова) в C++? Подробное руководство
Почему простое решение через stringstream не всегда подходит?
Ваш пример с stringstream работает только для разделения по пробелам. Для произвольных разделителей нужно использовать другие подходы. Рассмотрим три современных и безопасных способа.
Способ 1: Разделение по одному символу-разделителю
Самый простой способ для одного разделителя — использовать std::getline с stringstream:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::vector<std::string> splitByChar(const std::string& str, char delimiter) {
std::vector<std::string> tokens;
std::stringstream ss(str);
std::string token;
while (std::getline(ss, token, delimiter)) {
if (!token.empty()) {
tokens.push_back(token);
}
}
return tokens;
}
int main() {
std::string data = "apple,banana,orange,grape";
auto tokens = splitByChar(data, ',');
for (const auto& t : tokens) {
std::cout << t << " ";
}
// Вывод: apple banana orange grape
return 0;
}
Способ 2: Разделение по нескольким разделителям (современный C++)
Для нескольких разделителей используем std::find_first_of и итераторы:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
std::vector<std::string> splitByMultiple(const std::string& str, const std::string& delimiters) {
std::vector<std::string> tokens;
size_t start = 0;
size_t end = str.find_first_of(delimiters);
while (end != std::string::npos) {
if (end != start) {
tokens.push_back(str.substr(start, end - start));
}
start = end + 1;
end = str.find_first_of(delimiters, start);
}
if (start < str.length()) {
tokens.push_back(str.substr(start));
}
return tokens;
}
int main() {
std::string data = "apple,banana;orange|grape";
auto tokens = splitByMultiple(data, ",;|");
for (const auto& t : tokens) {
std::cout << t << " ";
}
// Вывод: apple banana orange grape
return 0;
}
Способ 3: Использование регулярных выражений (C++11)
Самый гибкий, но немного медленный способ:
#include <iostream>
#include <string>
#include <vector>
#include <regex>
std::vector<std::string> splitByRegex(const std::string& str, const std::string& pattern) {
std::vector<std::string> tokens;
std::regex re(pattern);
std::sregex_token_iterator it(str.begin(), str.end(), re, -1);
std::sregex_token_iterator end;
while (it != end) {
tokens.push_back(*it);
++it;
}
return tokens;
}
int main() {
std::string data = "Hello, world! This is C++";
// Разделяем по пробелам и знакам препинания
auto tokens = splitByRegex(data, R"([\s,;:.!?]+)");
for (const auto& t : tokens) {
std::cout << t << " ";
}
// Вывод: Hello world This is C++
return 0;
}
Что выбрать?
- Один разделитель — используйте
std::getline(просто и быстро). - Несколько символов-разделителей —
find_first_of(хорошая производительность). - Сложные паттерны разделения — регулярные выражения (максимальная гибкость, но медленнее).
Избегайте strtok из C — он модифицирует исходную строку и небезопасен. Все приведённые решения работают с std::string и совместимы с C++11 и новее.
Альтернативный подход: использование boost::algorithm::split
Если вы используете библиотеку Boost (а это очень популярная библиотека для C++), то задача упрощается до одной строки:
#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
int main() {
std::string str = "apple,banana;orange|grape";
std::vector<std::string> tokens;
boost::split(tokens, str, boost::is_any_of(",;|"));
for (const auto& t : tokens) {
std::cout << t << " ";
}
// Вывод: apple banana orange grape
return 0;
}
boost::split автоматически обрабатывает пустые токены (их можно исключить с помощью boost::token_compress_on). Это самый короткий и надёжный вариант, если Boost уже подключён к проекту.
Также можно использовать boost::tokenizer для более сложных случаев:
#include <boost/tokenizer.hpp>
std::string str = "Hello, world! This is C++";
boost::tokenizer<boost::char_separator<char>> tokens(str, boost::char_separator<char>(" ,;:.!?"));
for (const auto& t : tokens) {
std::cout << t << " ";
}
Оба подхода из Boost — это production-ready решения, которые используются в тысячах проектов. Если вы не хотите подключать Boost, используйте решения из первого ответа — они тоже отлично работают.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги