在 C++ 中分隔字符串

Separating a string in 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 以不同的方式对待 |||,而不是让它说它们相同?

#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 只是 returns 字符串中找到标记的位置,因此您必须手动检查返回的标记的第一个字符,看它是否也是“|”,然后采取相应的行动。

更好的解决方案是在此处查看正则表达式的使用。听起来你想要拆分的符号不仅仅是一个 |,而是一个 |被 space 包围——也就是说,您实际上是在搜索和拆分一个三字符符号 (space - 管道 - space)

我会说你的问题的答案首先是不要使用 strtok(),它有很多问题,甚至在联机帮助页中都有记录(至少在 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;
}

一个相当简单直接的解决方案,似乎可以解决您的问题。

The std::string::find() searches the string for the first occurrence of the sequence specified by its arguments (in this case the string 'delimiter'). When pos is specified, the search only includes characters at or after position 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;
    }

输出 :

错误 ||回声 "hello world"

grep 你好