分解字串成Token

偶爾我們會需要自己將字串分解成一個個的Token,對於簡單的需求我們通常都自己來,而不特別使用Tokenizer。使用C語言的話,我們會用strtok這個函式來完成我們的需求,不過我比較偏好C++的作法。
string s("this is a string");
vector<string> v;

v.assign(
  istream_iterator<string>(stringstream(s)),
  istream_iterator<string>()
);
如上所示,執行後v的內容會包含4個Token:this, is, a, string。

有一點要提醒的是,因為stringstream的Ctor會對s作copy的動作而不是直接使用s作為來源,所以當s的是一個很大的字串的話,在效能上會受到影響。

上面的範例在分解字串時是以空白字元作分隔,那假如要使用其它不同的字元作分隔符號該怎麼作呢?

getline可以提供這基本的需求。
stringstream ss(s);
string token;

for (;;)
{
  getline(ss, token, ',');
  if (ss.fail())
    break;

  cout << token << endl;
}
上面這個範例示範使用getline以','字元作分隔符號將字串分解。

+ + +

反向的操作有很多作法,底下舉一個STL的作法。
stringstream ss;

copy(
  v.begin(), v.end(),
  ostream_iterator<string>(ss, " ")
);

string s(ss.str());
stringstream的str方法也會產生一份新的string,所以當字串很大時效能也會受到影響。

留言

  1. 請問 sstream 可以一次依據多個 delimiter 切字串嗎?
    像 strtok(str, " ,\n\r\t") 這樣?

    回覆刪除
  2. 雖然不是更簡捷,但能解決問題
    提供一個方法,使用間接的方式

    ;

    string s("this, is; a\tstring");
    string delimiter(",;\n\r\t");

    size_t i = 0;
    while(string::npos != (i = s.find_first_of(delimiter, i)))
    s.replace(i, 1, " ");

    vector v;
    v.assign(istream_iterator(stringstream(s)), istream_iterator());

    回覆刪除

張貼留言

這個網誌中的熱門文章

以lex/yacc實作算式計算機

猜數字遊戲 (電腦猜人)

KillSudoku 4顆星精彩數獨詳解 - 鍊技巧