#опытным
Продолжаем рассказывать, как в плюсах можно делать то же самое, что всегда можно было делать в питоне и во всех современных языках.
Вот надо мне разделить слова в предложении по пробелам. Я просто беру и пишу:
text2 = "one two three four"
parts2 = text2.split()
print(parts2) # ['one', 'two', 'three', 'four']
А как сделать
Стандартных алгоритмов, делающих split нам не завезли, поэтому можно воспользоваться нестандартными. Например, бустом:
std::string text = "one two three four";
std::vector<std::string> strs;
boost::split(strs, text, boost::is_any_of(" "));
for (const auto &item : strs) {
std::cout << item << " ";
}
// OUTPUT: one two three four
Это прекрасно работает. Но кто-то не хочет тянуть к себе буст, кому-то не нравятся output параметры. В общем решение неидеальное, как пицца без мяса.
Поэтому люди городили свои огороды через find, стримы и прочее.
Но хочется чего-то родного.. Чего-то стандартного...
И аллилуя! В С++20 появились рэнджи, вместе с std::views::split:
auto range = text | std::views::split(' ');
for (const auto &item : range) {
std::cout << item << " ";
}
// OUTPUT: one two three fourЕсли вам нужен вектор значений, чтобы по индексам получать доступ, можно сделать так:
auto strs = text
| std::views::split(' ')
| std::ranges::to<std::vector<std::string>>();
std::print("{}", strs);
// OUTPUT: ["one", "two", "three", "four"]
Правда здесь уже нужен С++23 с его std::ranges::to.
У всех примеров есть особенность: если в исходной строке подряд идут несколько разделителей, то в результат попадают пустые строчки. Если вам так не нравится, то используйте std::views::filter:
std::string text = "one two three four";
auto strs = text | std::views::split(' ') |
std::views::filter(
[](auto &&sub_range) { return !sub_range.empty(); }) |
std::ranges::to<std::vector<std::string>>();
std::print("{}", strs);
// OUTPUT: ["one", "two", "three", "four"]
Все примеры можете найти здесь.
И жить стала еще чуть прекрасней)
Never too late. Stay cool.
#cpp20 #cpp23