我在StackOverflow上调查了一段时间,找到了将多个分隔符的字符串拆分成vector< string >
的好算法。我还找到了一些方法:
Boost方式:
boost::split(vector, string, boost::is_any_of(" \t"));
getline
方法:
std::stringstream ss(string);
std::string item;
while(std::getline(ss, item, ' ')) {
vector.push_back(item);
}
Boost的标记化方式:
char_separator<char> sep(" \t");
tokenizer<char_separator<char>> tokens(string, sep);
BOOST_FOREACH(string t, tokens)
{
vector.push_back(t);
}
和酷STL方式:
istringstream iss(string);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter<vector<string> >(vector));
和Shadow2531的方法(参见链接主题)。
他们大多来自this topic。但不幸的是他们没有解决我的问题:
Boost的分割很容易使用,但是大数据(大多数情况下大约1.5 * 10 ^ 6个单元)和大约10个分隔符我使用它的速度非常慢。
getline
,STL和Shadow2531的方法存在的问题是我只能使用一个char作为分隔符。我需要更多。
Boost的标记化在速度方面更加可怕。用10个分隔符花了11秒钟将一个字符串分成1.5 * 10 ^ 6个元素。
所以我不知道该怎么做:我希望有一个非常快速的字符串拆分算法和多个分隔符。
Boost的分裂是最大值还是有办法更快?
答案 0 :(得分:33)
我想到了两件事:
find
进入分隔符
字符。以下是应用这些想法的快速尝试:
#include <vector>
#include <bitset>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/timer.hpp>
using namespace std;
size_t const N = 10000000;
template<typename C>
void test_custom(string const& s, char const* d, C& ret)
{
C output;
bitset<255> delims;
while( *d )
{
unsigned char code = *d++;
delims[code] = true;
}
typedef string::const_iterator iter;
iter beg;
bool in_token = false;
for( string::const_iterator it = s.begin(), end = s.end();
it != end; ++it )
{
if( delims[*it] )
{
if( in_token )
{
output.push_back(typename C::value_type(beg, it));
in_token = false;
}
}
else if( !in_token )
{
beg = it;
in_token = true;
}
}
if( in_token )
output.push_back(typename C::value_type(beg, s.end()));
output.swap(ret);
}
template<typename C>
void test_strpbrk(string const& s, char const* delims, C& ret)
{
C output;
char const* p = s.c_str();
char const* q = strpbrk(p+1, delims);
for( ; q != NULL; q = strpbrk(p, delims) )
{
output.push_back(typename C::value_type(p, q));
p = q + 1;
}
output.swap(ret);
}
template<typename C>
void test_boost(string const& s, char const* delims)
{
C output;
boost::split(output, s, boost::is_any_of(delims));
}
int main()
{
// Generate random text
string text(N, ' ');
for( size_t i = 0; i != N; ++i )
text[i] = (i % 2 == 0)?('a'+(i/2)%26):((i/2)%2?' ':'\t');
char const* delims = " \t[],-'/\\!\"§$%&=()<>?";
// Output strings
boost::timer timer;
test_boost<vector<string> >(text, delims);
cout << "Time: " << timer.elapsed() << endl;
// Output string views
typedef string::const_iterator iter;
typedef boost::iterator_range<iter> string_view;
timer.restart();
test_boost<vector<string_view> >(text, delims);
cout << "Time: " << timer.elapsed() << endl;
// Custom split
timer.restart();
vector<string> vs;
test_custom(text, delims, vs);
cout << "Time: " << timer.elapsed() << endl;
// Custom split
timer.restart();
vector<string_view> vsv;
test_custom(text, delims, vsv);
cout << "Time: " << timer.elapsed() << endl;
// Custom split
timer.restart();
vector<string> vsp;
test_strpbrk(text, delims, vsp);
cout << "Time: " << timer.elapsed() << endl;
// Custom split
timer.restart();
vector<string_view> vsvp;
test_strpbrk(text, delims, vsvp);
cout << "Time: " << timer.elapsed() << endl;
return 0;
}
使用GCC 4.5.1使用启用了-O4
标志的Boost 1.46.1进行编译,得到:
注意:输出略有不同,因为我的自定义功能会丢弃空标记。但是,如果您决定使用它,您可以根据自己的需要调整此代码。
答案 1 :(得分:2)
要结合Pablo和larsmans答案的最佳部分,请使用(offset, size)
对来存储子字符串,使用strcspn
来获取每个条目的范围。
答案 2 :(得分:1)