我在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
用>=作为分隔符,这样我就可以得到斯科特和老虎。
template<typename C, typename T>
auto insert_in_container(C& c, T&& t) -> decltype(c.push_back(std::forward<T>(t)), void()) {
c.push_back(std::forward<T>(t));
}
template<typename C, typename T>
auto insert_in_container(C& c, T&& t) -> decltype(c.insert(std::forward<T>(t)), void()) {
c.insert(std::forward<T>(t));
}
template<typename Container>
Container splitR(const std::string& input, const std::string& delims) {
Container out;
size_t delims_len = delims.size();
auto begIdx = 0u;
auto endIdx = input.find(delims, begIdx);
if (endIdx == std::string::npos && input.size() != 0u) {
insert_in_container(out, input);
}
else {
size_t w = 0;
while (endIdx != std::string::npos) {
w = endIdx - begIdx;
if (w != 0) insert_in_container(out, input.substr(begIdx, w));
begIdx = endIdx + delims_len;
endIdx = input.find(delims, begIdx);
}
w = input.length() - begIdx;
if (w != 0) insert_in_container(out, input.substr(begIdx, w));
}
return out;
}
这与其他答案相似,但它使用了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();
}
我查看了答案,没有看到一个基于迭代器的方法可以被送入范围循环,所以我做了一个。
这使用了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: ''
它正确地处理字符串开头和结尾的空项。