我在c++中使用以下方法解析字符串:

using namespace std;

string parsed,input="text to be parsed";
stringstream input_stringstream(input);

if (getline(input_stringstream,parsed,' '))
{
     // do some processing.
}

使用单个字符分隔符进行解析是可以的。但是如果我想使用字符串作为分隔符呢?

例子:我想拆分:

scott>=tiger

用>=作为分隔符,这样我就可以得到斯科特和老虎。


当前回答

这与其他答案相似,但它使用了string_view。这些是原始字符串的视图。类似于c++20的例子。虽然这将是一个c++17的例子。(编辑以跳过空匹配)

#include <algorithm>
#include <iostream>
#include <string_view>
#include <vector>
std::vector<std::string_view> split(std::string_view buffer,
                                    const std::string_view delimeter = " ") {
  std::vector<std::string_view> ret{};
  std::decay_t<decltype(std::string_view::npos)> pos{};
  while ((pos = buffer.find(delimeter)) != std::string_view::npos) {
    const auto match = buffer.substr(0, pos);
    if (!match.empty()) ret.push_back(match);
    buffer = buffer.substr(pos + delimeter.size());
  }
  if (!buffer.empty()) ret.push_back(buffer);
  return ret;
}
int main() {
  const auto split_values = split("1 2 3 4 5 6 7 8 9     10 ");
  std::for_each(split_values.begin(), split_values.end(),
                [](const auto& str) { std::cout << str << '\n'; });
  return split_values.size();
}

其他回答

这是一个简洁的分裂函数。我决定让背靠背分隔符返回为空字符串,但您可以很容易地检查子字符串是否为空,如果是,则不将其添加到向量。

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



vector<string> split(string to_split, string delimiter) {
    size_t pos = 0;
    vector<string> matches{};
    do {
        pos = to_split.find(delimiter);
        int change_end;
        if (pos == string::npos) {
            pos = to_split.length() - 1;
            change_end = 1;
        }
        else {
            change_end = 0;
        }
        matches.push_back(to_split.substr(0, pos+change_end));
        
        to_split.erase(0, pos+1);

    }
    while (!to_split.empty());
    return matches;

}

以下是我的看法。它处理边缘情况,并接受一个可选参数从结果中删除空条目。

bool endsWith(const std::string& s, const std::string& suffix)
{
    return s.size() >= suffix.size() &&
           s.substr(s.size() - suffix.size()) == suffix;
}

std::vector<std::string> split(const std::string& s, const std::string& delimiter, const bool removeEmptyEntries = false)
{
    std::vector<std::string> tokens;

    for (size_t start = 0, end; start < s.length(); start = end + delimiter.length())
    {
         size_t position = s.find(delimiter, start);
         end = position != std::string::npos ? position : s.length();

         std::string token = s.substr(start, end - start);
         if (!removeEmptyEntries || !token.empty())
         {
             tokens.push_back(token);
         }
    }

    if (!removeEmptyEntries &&
        (s.empty() || endsWith(s, delimiter)))
    {
        tokens.push_back("");
    }

    return tokens;
}

例子

split("a-b-c", "-"); // [3]("a","b","c")

split("a--c", "-"); // [3]("a","","c")

split("-b-", "-"); // [3]("","b","")

split("--c--", "-"); // [5]("","","c","","")

split("--c--", "-", true); // [1]("c")

split("a", "-"); // [1]("a")

split("", "-"); // [1]("")

split("", "-", true); // [0]()

我得到这个解。这很简单,所有的打印/值都在循环中(循环后不需要检查)。

#include <iostream>
#include <string>

using std::cout;
using std::string;

int main() {
    string s = "it-+is-+working!";
    string d = "-+";

    int firstFindI = 0;
    int secendFindI = 0;
    while (secendFindI != string::npos)
    {
        secendFindI = s.find(d, firstFindI);
        cout << s.substr(firstFindI, secendFindI - firstFindI) << "\n"; // print sliced part
        firstFindI = secendFindI + d.size(); // add to the search index
    }
}

感谢@SteveWard改进了这个答案。

你也可以使用regex:

std::vector<std::string> split(const std::string str, const std::string regex_str)
{
    std::regex regexz(regex_str);
    std::vector<std::string> list(std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
                                  std::sregex_token_iterator());
    return list;
}

这相当于:

std::vector<std::string> split(const std::string str, const std::string regex_str)
{
    std::sregex_token_iterator token_iter(str.begin(), str.end(), regexz, -1);
    std::sregex_token_iterator end;
    std::vector<std::string> list;
    while (token_iter != end)
    {
        list.emplace_back(*token_iter++);
    }
    return list;
}

像这样使用它:

#include <iostream>
#include <string>
#include <regex>

std::vector<std::string> split(const std::string str,
                               const std::string regex_str) {
    std::regex regexz(regex_str);
    return {std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
            std::sregex_token_iterator()};
}

int main()
{
    std::string input_str = "lets split this";
    std::string regex_str = " "; 
    auto tokens = split(input_str, regex_str);
    for (auto& item: tokens)
    {
        std::cout<<item <<std::endl;
    }
}

在网上玩!

您可以简单地使用子字符串、字符等,或者使用实际的正则表达式来进行分割。 它也是简洁的c++ 11!

还有另一个答案:这里我使用find_first_not_of字符串函数,它返回第一个不匹配delim中指定的任何字符的位置。

size_t find_first_not_of(const string& delim, size_t pos = 0) const noexcept;

例子:

int main()
{
    size_t start = 0, end = 0;
    std::string str = "scott>=tiger>=cat";
    std::string delim = ">=";
    while ((start = str.find_first_not_of(delim, end)) != std::string::npos)
    {
        end = str.find(delim, start); // finds the 'first' occurance from the 'start'
        std::cout << str.substr(start, end - start)<<std::endl; // extract substring
    }
    return 0;
}

输出:

    scott
    tiger
    cat