我在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
用>=作为分隔符,这样我就可以得到斯科特和老虎。
我查看了答案,没有看到一个基于迭代器的方法可以被送入范围循环,所以我做了一个。
这使用了c++ 17 string_views,所以它不应该分配字符串的副本。
struct StringSplit
{
struct Iterator
{
size_t tokenStart_ = 0;
size_t tokenEnd_ = 0;
std::string str_;
std::string_view view_;
std::string delimiter_;
bool done_ = false;
Iterator()
{
// End iterator.
done_ = true;
}
Iterator(std::string str, std::string delimiter)
: str_{std::move(str)}, view_{str_}, delimiter_{
std::move(delimiter)}
{
tokenEnd_ = view_.find(delimiter_, tokenStart_);
}
std::string_view operator*()
{
return view_.substr(tokenStart_, tokenEnd_ - tokenStart_);
}
Iterator &operator++()
{
if (tokenEnd_ == std::string::npos)
{
done_ = true;
return *this;
}
tokenStart_ = tokenEnd_ + delimiter_.size();
tokenEnd_ = view_.find(delimiter_, tokenStart_);
return *this;
}
bool operator!=(Iterator &other)
{
// We only check if both points to the end.
if (done_ && other.done_)
{
return false;
}
return true;
}
};
Iterator beginIter_;
StringSplit(std::string str, std::string delim)
: beginIter_{std::move(str), std::move(delim)}
{
}
Iterator begin()
{
return beginIter_;
}
Iterator end()
{
return Iterator{};
}
};
示例用法如下:
int main()
{
for (auto token : StringSplit{"<>foo<>bar<><>bar<><>baz<><>", "<>"})
{
std::cout << "TOKEN: '" << token << "'" << std::endl;
}
}
打印:
TOKEN: ''
TOKEN: 'foo'
TOKEN: 'bar'
TOKEN: ''
TOKEN: 'bar'
TOKEN: ''
TOKEN: 'baz'
TOKEN: ''
TOKEN: ''
它正确地处理字符串开头和结尾的空项。
对于字符串(或单个字符)分隔符,这应该非常有效。不要忘记包含#include <sstream>。
std::string input = "Alfa=,+Bravo=,+Charlie=,+Delta";
std::string delimiter = "=,+";
std::istringstream ss(input);
std::string token;
std::string::iterator it;
while(std::getline(ss, token, *(it = delimiter.begin()))) {
std::cout << token << std::endl; // Token is extracted using '='
it++;
// Skip the rest of delimiter if exists ",+"
while(it != delimiter.end() and ss.peek() == *(it)) {
it++; ss.get();
}
}
第一个while循环使用字符串分隔符的第一个字符提取一个标记。第二个while循环跳过分隔符的其余部分,停在下一个标记的开头。
作为奖励,这里有一个分割函数和宏的代码示例,很容易使用,你可以在其中选择容器类型:
#include <iostream>
#include <vector>
#include <string>
#define split(str, delim, type) (split_fn<type<std::string>>(str, delim))
template <typename Container>
Container split_fn(const std::string& str, char delim = ' ') {
Container cont{};
std::size_t current, previous = 0;
current = str.find(delim);
while (current != std::string::npos) {
cont.push_back(str.substr(previous, current - previous));
previous = current + 1;
current = str.find(delim, previous);
}
cont.push_back(str.substr(previous, current - previous));
return cont;
}
int main() {
auto test = std::string{"This is a great test"};
auto res = split(test, ' ', std::vector);
for(auto &i : res) {
std::cout << i << ", "; // "this", "is", "a", "great", "test"
}
return 0;
}
以防将来,有人想跳出Vincenzo Pii答案的盒子函数
#include <vector>
#include <string>
std::vector<std::string> SplitString(
std::string str,
std::string delimeter)
{
std::vector<std::string> splittedStrings = {};
size_t pos = 0;
while ((pos = str.find(delimeter)) != std::string::npos)
{
std::string token = str.substr(0, pos);
if (token.length() > 0)
splittedStrings.push_back(token);
str.erase(0, pos + delimeter.length());
}
if (str.length() > 0)
splittedStrings.push_back(str);
return splittedStrings;
}
我还修复了一些错误,以便如果字符串的开头或结尾有分隔符,函数将不会返回空字符串