字符串分割函数是程序开发中常用的函数。实现比较简单,这儿是我的实现:
using namespace std;
template<class Functor>
void __SpliteString(TCHAR* p, const TCHAR cTok, Functor func)
{
TCHAR* e = p;
do
{
e = _tcschr(p, cTok);
if (e != NULL)
*e++ =_T('\0');
func(p);
p = e;
}while(p != NULL);
}
template<class Functor>
void SpliteString(const TCHAR* psz, const TCHAR cTok, Functor func)
{
string str = psz;
__SpliteString((TCHAR*)str.c_str(), cTok, func);
}
template<class Functor>
void __SpliteString(TCHAR* p, const TCHAR* szTok, Functor func)
{
TCHAR* e = p;
do
{
e = _tcsstr(p, szTok);
if (e != NULL)
*e++ =_T('\0');
func(p);
p = e;
}while(p != NULL);
}
template<class Functor>
void SpliteString(const TCHAR* psz, const TCHAR* szTok, Functor func)
{
string str = psz;
__SpliteString((TCHAR*)str.c_str(), szTok, func);
}
代码非常简单就不多做解释了。下面给出应用实例:
typedef vector<string> string_vector;
typedef string_vector::iterator string_iterator;
struct IntoVector
{
IntoVector(string_vector& str_vec) : _str_vec(str_vec){}
void operator()(const TCHAR* str)
{
_str_vec.push_back(str);
}
string_vector& _str_vec;
};
void println(const string& str)
{
cout<<str<<endl;
}
void main()
{
TCHAR szSource[] = "hello|this|is|a|test|string";
string_vector splited;
SpliteString(szSource, '|', IntoVector(splited));
for_each(splited.begin(), splited.end(), println);
}
以上代码把字符串按照竖线分割符分割后,放入一个vector容器中,并分行打印。
如果又想返回切割后字符串个数呢?改动一下:
typedef vector<string> string_vector;
typedef string_vector::iterator string_iterator;
struct IntoVector
{
IntoVector(string_vector& str_vec) : _str_vec(str_vec),_count(0){}
void operator()(const TCHAR* str)
{
_str_vec.push_back(str);
++ _count;
}
string_vector& _str_vec;
int _count;
};
void println(const string& str)
{
cout<<str<<endl;
}
void main()
{
TCHAR szSource[] = "hello|this|is|a|test|string";
string_vector splited;
IntoVector intovector(splited);
SpliteString(szSource, '|', (IntoVector&)intovector);
for_each(splited.begin(), splited.end(), println);
cout<<intovector._count<<endl;
}
看起来很完美:为了防止拷贝重新构造IntoVector对象,特地强制类型转换为 IntoVector的引用。事实总是让人意外又恼火的,打印结果还是0。跟踪结果就可以发现SpliteString传递的还是IntoVector拷 贝构造后的对象,而并不是引用。原因不是这儿探讨的范围,让我表达我也表达不清楚。不过解决办法还是有的。
方法1. 把count作为外部对象引用传入:
struct IntoVector
{
IntoVector(string_vector& str_vec,int count) : _str_vec(str_vec),_count(count){}
void operator()(const TCHAR* str)
{
_str_vec.push_back(str);
++ _count;
}
string_vector& _str_vec;
int& _count;
};
void main()
{
TCHAR szSource[] = "hello|this|is|a|test|string";
string_vector splited;
int count;
IntoVector intovector(splited, count);
SpliteString(szSource, '|', intovector);
for_each(splited.begin(), splited.end(), println);
cout<<count<<endl;
}
方法2. 当然还有更好的解决方式。boost是个好东西只需要修改一行就OK
SpliteString(szSource, '|', boost::bind<void>(boost::ref(intovector), _1));
为什么这么写?不是这儿的讨论范围了。查看一下boost源代码会很有帮助。
方法3. 这个是个ugly的办法——修改SpliteString的函数,将传递的Functor改成引用:
void SpliteString(const TCHAR* psz, const TCHAR* szTok, Functor& func);
void __SpliteString(const TCHAR* psz, const TCHAR* szTok, Functor& func);
结果就是你只能使用仿函数而不能直接传递函数指针了,so ugly,所以不要考虑这种方式。