在C++中分离字符串

13

我正在尝试将一个字符串分成多个字符串,以制作自定义终端。目前我已经使用strtok分离控制信号,但是我不知道如何分离特定字符的实例。例如:

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

当尝试对input使用strtok并使用|进行分离时,输出结果为:

false , echo "hello world" , grep hello

相反,我希望输出结果为:

false || echo "hello world" , grep hello

我该如何让strtok区别对待|||而不是认为它们是相同的?


1
“如何让strtok将|和||视为不同而不是相同?”,这是因为strtok将第二个参数中的每个字符都视为分隔符。此外,它不会返回空字符串。相关链接1,2 - Spikatrix
5个回答

8
#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;
    });

}

丑陋而冗长!但是有效!


问题是,如果用户想要使用“||”来分隔字符串,您将如何更改代码?因为使用您的代码不起作用,因为“char delim”必须只是一个字符。 另外感谢您,如果您只想查找单个分隔符,它可以完美地工作。 - divyanshch
1
那很容易解决,只需用一个字符串替换它即可。然而,使用多个可能的分隔符是一个不太容易添加的功能。 - Ulrich Eckhardt

1
#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;
}

1

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

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 || echo "hello world"

grep hello


这段代码在以下情况下无法正常工作:echo "hello world" | grep hello | grep world预期输出应为:echo "hello world" grep hello grep world但实际输出却是:echo "hello world" | grep hello grep world - divyanshch

1

strtok()将逐个扫描字符,而不考虑它要查找的字符前后的字符。如果你想要更智能的扫描,你需要自己实现额外的检查。

由于strtok只返回字符串中找到标记的位置,因此您必须手动检查返回的标记的第一个字符是否也是'|',然后相应地采取行动。

更好的解决方案是在这里使用正则表达式。听起来,你想要分割的符号不仅仅是|,而是被空格包围的| - 也就是说,你实际上正在搜索和分割三个字符的符号(空格 - 管道 - 空格)。


1
我认为回答你的问题首先不要使用strtok(),因为它有许多问题,这些问题甚至在man页上有记录(至少在Linux上是如此)。
其次,请确保您有测试。对于这些任务,使用测试驱动开发是必须的,因为在这里,几个简单的事情可能会相互交错,并且修复一个地方的错误可能会导致另一个地方出现问题。
此外,有一些工具(例如各种YACC变体和类似的生成器),可以让您指定抽象语法,然后将此定义转换为C++代码。我建议任何非平凡的任务都使用这些工具。
最后,如果您只是为了娱乐和学习而这样做,编写循环或一组函数以从字符串中提取各种标记是一个好方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接