Сплит строки

Не подскажите как грамотно на С++ сделать «сплит» строки? Т.е. надо входную строку разбить на подстроки по одному или нескольким символам-разделителям. Как это сделать на С я в общих чертах представляю. Как это сделать со string — не понимаю. Доставать из string сырую строку вроде как-то не по полюсовому.

А вообще-то в итоге мне надо получить char *arg[] для передачи в системный вызов. Тоже вопрос как этот массив техничнее сделать.

Поправочка:

А вообще-то в итоге мне надо получить char *arg[] для передачи в системный вызов.

char *const arg[]

Например, такой вариант:

#include <iostream>
#include <iterator>


#include <string>

#include <vector>
#include <algorithm>

template<
    typename Iterator,
    typename Func,
    template <typename...> class Container = std::vector
>
Container<std::pair<Iterator, Iterator>> 
splitString(
    Iterator begin, 
    Iterator end, 
    Func func
)
{
    std::vector<std::pair<Iterator, Iterator>> result;
    Iterator first = begin;
    Iterator last = begin;
    do {
        first = std::find_if_not(last, end, func);
        if (first == end) {
            break;
        }
        last = std::find_if(first, end, func);
        result.emplace_back(first, last);
    }while (first != end);         
    return result;
}



int 
main()
{

    std::string str = ".My nick is Croessmah. I am coolhacker!!! It is jape. :)";

    for (auto &p: splitString(str.begin(), str.end(), [](char x) {return isspace(x) || ispunct(x);})) {
        std::cout << std::string(p.first, p.second) << std::endl;
    }
}

http://rextester.com/DOCR17423

Спасибо за ответ!
Крута. Основная идея алгоритма понятна. Но WTF! Как???

Зачем здесь темплейт? Итератор для string вроде можно и напрямую описать.

Строку template <typename...> class Container = std::vector я вообще не понял. Т.е. смысл то понятен: что бы функция возвращала вектор пар итераторов. Но не могли бы вы объяснить почему надо написать именно так?

С Func тоже не понял. Опять таки общий смысл «зачем» понятен, непонятно «как». Если смотреть по коду, Funk — некий тип. В функцию вы передаете переменную этого типа, которую дальше используете как указатель на функцию. Причем Funk не содержит никакой информации о контракте (кажется это так называется?) функции, и даже нет никаких указаний, что это вообще указатель на функцию. Каким образом лямбда из main без ошибок компиляции просачивается в вызов find_if?

И еще не понял зачем в функции нужно условие в цикле do { ... } while (first != end). Мне кажется, что здесь можно использовать безконечный цикл. Не?

int main()
{
    char text[] = ".My nick is Croessmah. I am coolhacker!!! It is jape. :)";
    char symbols[] = "!. :)";
    std::vector<char*> results;

    char * pch = strtok(text, symbols);
    while (pch != NULL)
    {
        results.push_back(pch);
        pch = strtok(NULL, symbols);
    }

    // use

    for (const auto& str : results)
    {
        std::system((std::string("title ") + str).c_str());
        Sleep(500);
    }

    return 0;
}

Зачем здесь темплейт?

Да просто валялась писанина.
Несмотря на то, что здесь шаблон,
оно будет не везде работать,
потому как писалось через одно место.

Итератор для string вроде можно и напрямую описать.

А если захотим wstring поделить или какой-нибудь другой тип?
Причем это не обязательно должны быть символы.
По сути, это не разделение строки,
а разделение последовательности
по заданному правилу.

Но не могли бы вы объяснить почему надо написать именно так?

Здесь шаблонный параметр шаблона.
В силу того, что функция сама
инстанцирует шаблон контейнера
с заданным параметром,
то приходится передавать шаблон,
хотя можно и помудрить получше.
Ознакомьтесь со статьями о шаблонах:
https://code-live.ru/post/cpp-template-functions/
https://code-live.ru/post/cpp-templates-part-2/
Возможно, они будут Вам полезны.

Если смотреть по коду, Funk — некий тип.

Да, тип будет выведен из инициализатора.

Каким образом лямбда из main без ошибок компиляции просачивается в вызов find_if?

Из лямбда-выражения будет создан класс замыкания.
Собственно, Func и будет иметь тип класса замыкания.
И создается само замыкание — объект класса замыкания.

В функцию вы передаете переменную этого типа, которую дальше используете как указатель на функцию

Ознакомьтесь с понятием функтора,
это многое поставит на свои места. :)

Мне кажется, что здесь можно использовать безконечный цикл. Не?

ЕМНИП, то изначально внутренности
выглядели иначе, а после
переделки условие так и осталось,
в принципе, можно выкинуть.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.