向左右向右走 —— 小时了了的技术博客

关注C++开发技术、架构设计、软件项目管理、软件产品管理等

posts - 19,comments - 55,trackbacks - 0

  需求源于为博客文章添加tag的字符串处理: tag之间以“,”分隔,要根据这个分隔符分离出各个tag;另外处于习惯用户可能敲入多余的空格,所以需要对tag的左右空格进行剪切。STL的string类没有现成的方法只好自己写一个。第一版函数原型如下: 

void find_all_words(const string& str, char decollator, vector<string> words);

其中参数decollator表示分隔符,words用于存储分离出来的各个单词(tag)。

 

  考虑到vector没有排序的功能,调用者有可能期望把单词存储在list中,也可能根据需求的不同选择map或者其他类型的容器。所以第三个参数应该更灵活才行,可以考虑泛型但功能依然受限因为只能选择STL标准容器。

  需求是多种多样的,可能用户想存放成静态数组也可能想直接打印,那么这多种多样的需求究竟能否满足呢?答案是肯定的,别忘了在C++ 0x中有两样强大的武器function和lambda表达式,所以我们第二版的函数原型如下: 

void find_all_words(const string& str, char decollator, function<void(string&)> push);

 

  它的调用看起来是下面这个样子的:

 

list<string> words;
find_all_words(str,
',', [&words](string& s){ words.push_back(); });

 

  另外我们还需要对分离出来的单词做剪切操作,正常的处理逻辑是:“分离单词->剪切处理->存储单词”,当然我们可以拿到单词列表之后再挨个做剪切处理,但是这个逻辑就反了不太符合直觉而且会带来一定的效率开销(至少要再遍历一次列表),所以我们再次拿起c++ 0x的强大武器增加一个function类型的参数用于单词的预处理。函数的的调用就变成了下面的样子:

 

list<string> words;
auto push_word
= [&words](string& s){ words.push_back(); };
auto trim_word
= [](string& s){ trim(word, ''); };
find_all_words(str,
',', push_word, trim_word);

 

  函数原型已经确定剩下的算法问题就是小菜一碟了。函数的完整实现如下:

 

1 void find_all_words(const string& str, char decollator, function<void(string&)> push, function<void(string&)> pre = NULL)
2 {
3 string::size_type start_pos =0;
4 do
5 {
6 string::size_type dec_pos = str.find_first_of(decollator, start_pos);
7 string word = str.substr(start_pos, dec_pos - start_pos);
8 if (pre != NULL) pre(word);
9 if (word.length() >0) push(word);
10 start_pos = dec_pos !=string::npos ? dec_pos +1 : dec_pos;
11
12 } while (start_pos < str.length());
13 }

 

  剪切string左右字符的两个函数都比较简单,实现如下:

1 void trim_left(string& s, char c)
2 {
3 if(s.length() ==0) return;
4 string::size_type pos = s.find_first_not_of(c);
5 s.erase(0, pos);
6 }
7
8 void trim_right(string& s, char c)
9 {
10 if (s.empty()) return;
11 string::size_type pos = s.find_last_not_of(c);
12 pos ==string::npos ? s.clear() : s.erase(pos +1, s.length() - pos -1);
13 }
14
15 void trim(string& s, char c)
16 {
17 trim_right(s, c);
18 trim_left(s, c);
19 }
20  

 

  以前很少写字符串处理的程序,就是偶尔要写也习惯了用标准C函数,好处是你完全清楚每一步的操作是怎样完成的,不像string是一个神奇的黑盒子。当然更主要的原因懒得去学STL string中的一大堆方法(更郁闷的是一个方法可以有十几种重载),现在初步尝试了一下确实还是挺方便的。看来做程序员还是要抱着开放的心态多尝试新东西才好。

 

 

posted on 2011-01-22 15:56 小时了了 阅读(...) 评论(...) 编辑 收藏