Разделение строки в C++

Я пытаюсь разделить строку на несколько строк, чтобы сделать настроенный терминал. До сих пор я разделял управляющие сигналы с помощью strtok, однако я не понимаю, как отделить конкретные экземпляры символа. Например:

string input = "false || echo "hello world" | grep hello";

при попытке strtok это input и пытается отделить с помощью | выход будет:

false , echo "hello world" , grep hello

вместо этого, я хотел бы вывод должен быть:

false || echo "hello world" , grep hello

как я могу иметь strtok лечить | и || по-другому, а не то, что он говорит, что они одинаковы?

5 ответов


#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;

vector<string> split(string sentence,char delim)
{
    string tempSentence = "";
    tempSentence += delim;
    tempSentence += sentence;
    tempSentence += delim;

     string token;
     vector<string> tokens;
    for (int i=1;i<tempSentence.length()-1;++i)
    {
        if (tempSentence[i] == delim && tempSentence[i-1] != delim && tempSentence[i+1] != delim)
        {
            if (token.length()) tokens.push_back(token);
            token.clear();
        }
        else
        {
            token += tempSentence[i];
        }
    }
    if (token.length()) tokens.push_back(token);

    return tokens;
}

int main() {
    string sentence = "false || echo \"hello world\" | grep hello";
    char delim='|';

    vector<string> tokens = split(sentence,delim);


    for_each(tokens.begin(), tokens.end(), [&](string t) {   
        cout << t << endl;
    });

}

некрасиво и долго! но работает!


strtok () будет сканировать символ за символом, без учета символов до и после того, что он ищет. Если вы хотите более Умное сканирование, вам нужно будет реализовать дополнительную проверку самостоятельно.

поскольку strtok просто возвращает местоположение в строке, где найден токен, вам придется вручную проверить первый символ возвращаемого токена, чтобы увидеть, является ли он также"|", а затем действовать соответственно.

лучшим решением было бы изучить использование регулярного выражения здесь. Похоже, что символ, который вы хотите разделить, - это не просто A|, а скорее a/, окруженный пробелами, т. е. вы фактически ищете и разделяете символ из трех символов (space - pipe - space)


Я бы сказал, что ответ на ваш вопрос, во-первых, не использовать strtok(), который имеет множество проблем, которые даже задокументированы в manpage (по крайней мере, в Linux).

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

далее, есть инструменты (например, различные YACC-вариантов и подобные генераторы), которые позволяют определить абстрактный синтаксис, а затем превратить это определение в C++ код. Я бы предложил их для любой нетривиальной задачи.

наконец, если вы делаете это только для удовольствия и обучения, написание цикла или набора функций для извлечения различных токенов из строки-хороший подход.


#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main() {
    string input = "false || echo \"hello world\" | grep hello";

    string::iterator itr;

    itr = input.begin();

    do {
        itr = search_n(itr, input.end(), 1, '|');

        if (itr < input.end() - 1)
        {
            if (*(itr + 1) == '|')
            {
                itr = itr + 2;
                continue;
            }
        }        

        if (itr < input.end())
        {
                *itr = ',';
                itr ++;
        }

    } while (itr < input.end());

    cout << input << endl;

    return 0;
}

довольно простое и простое решение, которое, кажется, решает ваш вопрос.

std:: string:: find() выполняет поиск в строке первого вхождения последовательности, заданной ее аргументами (в данном случае строка 'delimiter'). Когда pos указан, поиск включает только символы В или после позиции pos.

редактировать

    #include <iostream>
    #include <string>
    int main(int argc, char const *argv[])
    {
        std::string s = "false || echo \"hello world\" | grep hello";
        std::string delimiter = "|";

        size_t pos = 0, pos1 = 0, flag = 0;
        std::string token, token1;
        while ((pos = s.find(delimiter)) != std::string::npos) {
            pos1 = s.find(delimiter, pos + delimiter.length());
            while (pos1 == pos+1){
                pos = pos1;
                pos1 = s.find(delimiter, pos + delimiter.length());
                flag = 1;
            }
            if (flag) {
                token = s.substr(0, pos1);
                std::cout << token << std::endl;
                if (pos1 > s.length())
                    exit(0);
                s.erase(0, pos1 + delimiter.length());
            }
            else{
                token = s.substr(0, pos);
                std::cout << token << std::endl;
                s.erase(0, pos + delimiter.length());
            }

        }
        std::cout << s << std::endl;
        return 0;
    }

выход :

false / / Эхо "hello world"

grep привет