[程式設計] C++ 的字串切割
簡介
C++的字串切割,我看過解釋最詳細的是這篇。推薦大家看看。字串切割是撰寫程式中常有的需求,舉例來說
- 將一個字串依空白切割成數個子字串。如 "15 19 12" 切成 "15","19" 以及 "12"。
- 將字串依規定的符號切割成數個子字串。如 "15,19,12",切成 "15","19" 以及 "12",這是切割符號為逗點。
- 將字串依規定的符號切割成數個子字串,但這個符號可以有多種。例如 "15,19!12",切成 "15","19" 以及 "12",這是切割符號為 , 以及 !。
這篇文章,要談的,是最後一種的切割方式。
如果只有一種切割符號,那直接用 stringstream 以及 getline 就可以解決。
但多個切割符號,就很麻煩了。函式庫內建的 stringstream 以及 getline 並沒有法子達到這個功能,所以只能自己動手來搞定了。
好在 C++ 的字串有提供 find_first_of 這個字串的尋找函式,可以幫我們省下很多麻煩。
題外話,由於字串切割真的是很重要,而且常見的任務。這種自幹的作法也是會讓程式設計師增加很多麻煩,所以著名的 Boost 函式庫就提供了功能強大的 split 函式。祈禱這個功能可以加入下一版的 C++ 中囉 (例如 C++ 20 中)。
好了,要開始進入正文了,但先說明,底下版本會略掉「空字串」。
這什麼意思呢?看一下底下的例子。
"12,|15 19"
分割符號為 逗點,空白,以及 |。
可以看到 12 和 15 間夾了 ,|
這兩個符號間,夾了一個空字串,這個字串在底下的程式中,是會被忽略的。
find_first_of
find_first_of 是 C++ 字串的一個成員函式,它最常用的形式為
find_first_of("切割字元", 位置);
舉例來說
在上面的例子中, 我們要在 s 中,找到 " ,|" 中第一個出現的字元。
" ,|" 包含三個字元,即 空白,逗點,以及 |。 C++ 只要遇到其中一個,就會中斷尋找,並回傳所在的位置。
所以這個例子中, pos 為 2,因為第一個出現的分割字元為 逗點,它出現在字串的第 2 個位置。
substr 常用的形式為
substr( 位置, 長度 )
它會在字串中,由位置指定處,切出某個長度的子字串。
還是搭配個例子吧。
在上面的例子中, current 代表開始搜尋的位置。它的初始值為 0。
pos 為第一個分割字元的位值,其值為 2。
所以 pos - current 便為 2。也就是第一個子字串的長度。
因此第12行便印出 15 了。
" ,|" 包含三個字元,即 空白,逗點,以及 |。 C++ 只要遇到其中一個,就會中斷尋找,並回傳所在的位置。
所以這個例子中, pos 為 2,因為第一個出現的分割字元為 逗點,它出現在字串的第 2 個位置。
搭配 substr 來切出子字串
接著我們就可以用 substr 來把字串中的子字串找出來。substr 常用的形式為
substr( 位置, 長度 )
它會在字串中,由位置指定處,切出某個長度的子字串。
還是搭配個例子吧。
在上面的例子中, current 代表開始搜尋的位置。它的初始值為 0。
pos 為第一個分割字元的位值,其值為 2。
所以 pos - current 便為 2。也就是第一個子字串的長度。
因此第12行便印出 15 了。
把 while 加上去,切出所有的子字串吧!
瞭解這些後,我們就可以把前述的程式碼放到 loop 中,不斷的切割,就可以切出所有的子字串了。
在底下的例子中,會把所有的子字串都放到一個 vector 中,並且忽略空字串。
上面的程式碼中,我把字串切割的功能寫成了函式。
由 16 行開始,splitStr2Vec 會把字串中的子字串切割出來,並放入 vector 中。
current 變數代表搜尋的起點。
它的邏輯蠻簡單的,只要切出一個子字串後,若它不是空字串,就放到 vector 中。
然後更新 current 的位置,也就是改變搜尋的位置,由目前分割字元的「下一個」字元開始搜尋。
這個函式還有可以改善的地方。
例如我把 「分割字元」 寫死在函式中了,但其實分割字元可以當成參數傳給函式。
在底下的例子中,會把所有的子字串都放到一個 vector 中,並且忽略空字串。
上面的程式碼中,我把字串切割的功能寫成了函式。
由 16 行開始,splitStr2Vec 會把字串中的子字串切割出來,並放入 vector 中。
current 變數代表搜尋的起點。
它的邏輯蠻簡單的,只要切出一個子字串後,若它不是空字串,就放到 vector 中。
然後更新 current 的位置,也就是改變搜尋的位置,由目前分割字元的「下一個」字元開始搜尋。
結論
這篇文章談到了如何依照多個「分割字元」來切割子串。並且把切割字串的功能寫成了函式。這個函式還有可以改善的地方。
例如我把 「分割字元」 寫死在函式中了,但其實分割字元可以當成參數傳給函式。
可以解釋一下這段的作用嗎?
回覆刪除for (string tmp : buf)
cout << tmp << endl;
作者已經移除這則留言。
刪除這是一個C++比較新版的方法,可用冒號走訪vector各元素。
刪除感謝
回覆刪除謝謝分享!
回覆刪除不過這一段似乎有BUG哦
next = s.find_first_of(" ,|", current);
if (next != current)
{
string tmp = s.substr(current, next - current);
if (tmp.size() != 0) //忽略空字串
buf.push_back(tmp);
}
當 find() return -1 的時候,您的 substr 會是 s.substr(current, -1-current)
所以應該另外判斷!
Learn and apply all the latest language code with us here codeprozone.
回覆刪除