我在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++ 11开始,它可以这样做:
std::vector<std::string> splitString(const std::string& str,
const std::regex& regex)
{
return {std::sregex_token_iterator{str.begin(), str.end(), regex, -1},
std::sregex_token_iterator() };
}
// usually we have a predefined set of regular expressions: then
// let's build those only once and re-use them multiple times
static const std::regex regex1(R"some-reg-exp1", std::regex::optimize);
static const std::regex regex2(R"some-reg-exp2", std::regex::optimize);
static const std::regex regex3(R"some-reg-exp3", std::regex::optimize);
string str = "some string to split";
std::vector<std::string> tokens( splitString(str, regex1) );
注:
这是对这个答案的一个小小的改进
参见std::regex_constants::optimize使用的优化技术
我查看了答案,没有看到一个基于迭代器的方法可以被送入范围循环,所以我做了一个。
这使用了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: ''
它正确地处理字符串开头和结尾的空项。
Strtok允许您传入多个字符作为分隔符。我敢打赌,如果你传入“>=”,你的示例字符串将被正确分割(即使>和=被算作单独的分隔符)。
EDIT如果您不想使用c_str()将字符串转换为char*,您可以使用substr和find_first_of进行标记化。
string token, mystring("scott>=tiger");
while(token != mystring){
token = mystring.substr(0,mystring.find_first_of(">="));
mystring = mystring.substr(mystring.find_first_of(">=") + 1);
printf("%s ",token.c_str());
}
你也可以使用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!