我在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
用>=作为分隔符,这样我就可以得到斯科特和老虎。
下面是一个使用Boost string Algorithms库和Boost Range库将一个字符串与另一个字符串分割的示例。这个解决方案的灵感来自StringAlgo库文档,请参阅Split部分。
下面是split_with_string函数的完整程序,以及全面的测试-用godbolt试试:
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/range/iterator_range.hpp>
std::vector<std::string> split_with_string(std::string_view s, std::string_view search)
{
if (search.empty()) return {std::string{s}};
std::vector<boost::iterator_range<std::string_view::iterator>> found;
boost::algorithm::ifind_all(found, s, search);
if (found.empty()) return {};
std::vector<std::string> parts;
parts.reserve(found.size() + 2); // a bit more
std::string_view::iterator part_begin = s.cbegin(), part_end;
for (auto& split_found : found)
{
// do not skip empty extracts
part_end = split_found.begin();
parts.emplace_back(part_begin, part_end);
part_begin = split_found.end();
}
if (part_end != s.end())
parts.emplace_back(part_begin, s.end());
return parts;
}
#define TEST(expr) std::cout << ((!(expr)) ? "FAIL" : "PASS") << ": " #expr "\t" << std::endl
int main()
{
auto s0 = split_with_string("adsf-+qwret-+nvfkbdsj", "");
TEST(s0.size() == 1);
TEST(s0.front() == "adsf-+qwret-+nvfkbdsj");
auto s1 = split_with_string("adsf-+qwret-+nvfkbdsj", "-+");
TEST(s1.size() == 3);
TEST(s1.front() == "adsf");
TEST(s1.back() == "nvfkbdsj");
auto s2 = split_with_string("-+adsf-+qwret-+nvfkbdsj-+", "-+");
TEST(s2.size() == 5);
TEST(s2.front() == "");
TEST(s2.back() == "");
auto s3 = split_with_string("-+adsf-+qwret-+nvfkbdsj", "-+");
TEST(s3.size() == 4);
TEST(s3.front() == "");
TEST(s3.back() == "nvfkbdsj");
auto s4 = split_with_string("adsf-+qwret-+nvfkbdsj-+", "-+");
TEST(s4.size() == 4);
TEST(s4.front() == "adsf");
TEST(s4.back() == "");
auto s5 = split_with_string("dbo.abc", "dbo.");
TEST(s5.size() == 2);
TEST(s5.front() == "");
TEST(s5.back() == "abc");
auto s6 = split_with_string("dbo.abc", ".");
TEST(s6.size() == 2);
TEST(s6.front() == "dbo");
TEST(s6.back() == "abc");
}
测试输出:
PASS: s0.size() == 1
PASS: s0.front() == "adsf-+qwret-+nvfkbdsj"
PASS: s1.size() == 3
PASS: s1.front() == "adsf"
PASS: s1.back() == "nvfkbdsj"
PASS: s2.size() == 5
PASS: s2.front() == ""
PASS: s2.back() == ""
PASS: s3.size() == 4
PASS: s3.front() == ""
PASS: s3.back() == "nvfkbdsj"
PASS: s4.size() == 4
PASS: s4.front() == "adsf"
PASS: s4.back() == ""
PASS: s5.size() == 2
PASS: s5.front() == ""
PASS: s5.back() == "abc"
PASS: s6.size() == 2
PASS: s6.front() == "dbo"
PASS: s6.back() == "abc"
#include<iostream>
#include<algorithm>
using namespace std;
int split_count(string str,char delimit){
return count(str.begin(),str.end(),delimit);
}
void split(string str,char delimit,string res[]){
int a=0,i=0;
while(a<str.size()){
res[i]=str.substr(a,str.find(delimit));
a+=res[i].size()+1;
i++;
}
}
int main(){
string a="abc.xyz.mno.def";
int x=split_count(a,'.')+1;
string res[x];
split(a,'.',res);
for(int i=0;i<x;i++)
cout<<res[i]<<endl;
return 0;
}
注:仅当分割后的字符串长度相等时才有效
从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使用的优化技术