1.引入问题,用strtok解决问题
长期处理sip的字符串,经常需要分析text文本,比如从url中取user info,host,url param等等。
例如,以下就是一个典型的tel url.
tel:9812340014;tgrp=tg-1;trunk-context=example.com;phone-context=example.lab
为了获得其中的url param, 比如tgrp而去单独去写一个函数,成本太高,于是想到python中对字符串的操作十分便捷,可以直接调用split()方法,分段成一个list。
于是打算也写一个类似的函数,并做简单ut测试发现如下:
#include <stdio.h>
#include <string>
#include <string.h>
#include <list>
#define ccLog(fmt, args...)\
printf(fmt"\n",##args)
#define ccWarning(fmt, args...)\
printf(fmt"\n",##args)
using namespace std;
void strSplit(char* str, const char* pattern, list<string>& subStrList)
{
if(NULL == str || NULL == pattern) return;
ccLog("input str:%s", str);
char* pch = strtok(str, pattern);
while (pch != NULL)
{
ccLog("%s",pch);
string substr = pch;
subStrList.push_back(substr);
pch = strtok (NULL, pattern);
}
}
int main()
{
const char* uristr = "tel:9812340014;tgrp=tg-1;trunk-context=mavenir.com;phone-context=mavenir.lab";
list<string> strlist;
strSplit((char*)uristr, ":;", strlist);
list<string>::iterator it = strlist.begin();
list<string>::const_iterator itEnd = strlist.end();
for(;it!=itEnd;++it)
{
ccLog("substr:%s", it->c_str());
}
return 0;
}
2.出现异常
打开gdb调试发现问题出现在下面第一次调用strtok这一行。
Breakpoint 1, strSplit (str=0x401800 "tel:9812340014;tgrp=tg-1;trunk-context=example.com;phone-context=example.lab",
pattern=0x40184d ":;", subStrList=empty std::list) at urlparam.cpp:17
17 char* pch = strtok(str, pattern);
3.分析问题
于是查看了C++ Reference的定义和例子http://www.cplusplus.com/reference/cstring/strtok/
发现,每次返回的指针pch都能直接打印,即使不知道源码,也能猜到,strtok是把每个匹配的字符直接替换成‘\0’, 而且是在原来的字符串上修改,于是问题迎刃而解。
如果更细心的话,也会发现,C++ Reference定义说明上关于入参str这么说:Notice that this string is modified by being broken into smaller strings (tokens).
而且例子里用的是
char str[] ="- This, a sample string.";
而不是不可修改的字符串常量。
4.修改实现
修改strSplit函数如下:
void strSplit(string str, const char* pattern, list<string>& subStrList)
{
if(str.empty() || NULL == pattern) return;
ccLog("input str:%s", str.c_str());
char* pch;
pch = strtok ((char*)str.c_str(), pattern);
while (pch != NULL)
{
//ccLog("%s",pch);
string substr = pch;
subStrList.push_back(substr);
pch = strtok (NULL, pattern);
}
}
5.得出期望结果
编译输出结果如下:
input str:tel:9812340014;tgrp=tg-1;trunk-context=example.com;phone-context=example.lab
substr:tel
substr:9812340014
substr:tgrp=tg-1
substr:trunk-context=example.com
substr:phone-context=example.lab