C++实现字符串分割函数split()
目錄
使用strtok()完成分割
使用strsep()完成分割
使用strtok_r()完成分割
實(shí)現(xiàn)字符串分割
前言
最近遇到了一個(gè)字符串分割的問題,在C++的標(biāo)準(zhǔn)庫(kù)里面沒有字符分割函數(shù)split()。我想這個(gè)問題今后可能還會(huì)再遇見,所以使用C/C++中的字符串分割方法完成相應(yīng)的功能。
需求:對(duì)一個(gè)字符串進(jìn)行分割,然后將分割后的數(shù)據(jù)存起來(lái),想用的時(shí)候像用數(shù)組那樣拿就行了。所以在完成分割后,需要使用vector將相應(yīng)的數(shù)據(jù)保存起來(lái)。
?
使用strtok()完成分割
char * strtok ( char * str,const char * delim ); 其中str是需要分割的字符串。delim是分隔符標(biāo)識(shí)。 在<cstring>??<string.h>中定義該函數(shù)被設(shè)計(jì)為多次調(diào)用,以從同一字符串中獲取連續(xù)的token。
如果 str != NULL,該調(diào)用被視為 strtok 對(duì)此特定字符串的第一個(gè)調(diào)用。該函數(shù)搜索中不包含的第一個(gè)字符 delim。
? ? ? ? 如果找不到這樣的字符,則根本沒有標(biāo)記str,并且該函數(shù)返回空指針。
? ? ? ? 如果找到了這樣的字符,則這是token的開頭。然后,函數(shù)從該點(diǎn)開始搜索包含delim的第一個(gè)字符。
? ? ? ? ? ? ? ? 如果未找到這樣的字符,str則只有一個(gè)標(biāo)記,以后調(diào)用strtok將返回一個(gè)空指針
? ? ? ? ? ? ? ? 如果找到了這樣的字符,則將其替換為空字符'\0',并將指向下一個(gè)字符的指針存儲(chǔ)在靜態(tài)位置中,以供后續(xù)調(diào)用。
? ? ? ? 然后,該函數(shù)將指針返回到token的開頭
如果str == NULL,則該調(diào)用將被視為對(duì)后續(xù)調(diào)用strtok:該函數(shù)從上次調(diào)用中保留的位置繼續(xù)。行為與先前存儲(chǔ)的指針作為str傳遞的行為相同。
#include <cstring> #include <iostream>int main() {char input[100] = "A, bird, came, down, the, walk";char *token = std::strtok(input, ", ");while (token != NULL) {std::cout << token << '\n';token = std::strtok(NULL, ", ");} }筆記:
(1)此函數(shù)具有破壞性:它將 '\0' 字符寫入 str 字符串的元素中。
(2)每次對(duì)該函數(shù)的調(diào)用都會(huì)修改一個(gè)靜態(tài)變量:不是線程安全的。
(3)與大多數(shù)其他strtok不同,每個(gè)后續(xù)標(biāo)記中的定界符可以不同,甚至可以取決于先前標(biāo)記的內(nèi)容。
(4)其中delim可以包含多個(gè)分隔符,strtok函數(shù)會(huì)將str內(nèi)容按分隔符分割。如果對(duì)數(shù)據(jù)格式有要求,需要注意這一點(diǎn)。
?
源自百度百科:
下面的說(shuō)明摘自于Linux內(nèi)核2.6.29,說(shuō)明了這個(gè)函數(shù)已經(jīng)不再使用,由速度更快的strsep()代替。
/** linux/lib/string.c** Copyright (C) 1991, 1992 Linus Torvalds*//** stupid library routines.. The optimized versions should generally be found
* as inline code in <asm-xx/string.h>
* These are buggy as well..
* * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
* - Added strsep() which will replace strtok() soon (because strsep() is
* reentrant and should be faster). Use only strsep() in new code, please.
** * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
* Matthew Hawkins <matt@mh.dropbear.id.au>
* - Kissed strtok() goodbye
*/
?
使用strsep()完成分割
strsep函數(shù)用于分解字符串為一組字符串。其原型為:
char *strsep(char **s, const char *delim);?
存在的問題
#include <stdio.h> #include <stdlib.h> #include <string.h>//char *strsep(char **str, const char *delim); int main(void) {char source[] = "hello, world! welcome to china!";char delim[] = " ,!";char *input = strdup(source);char *token = strsep(&input, delim);while (token != NULL) {printf(token);printf("-");token = strsep(&input, delim);printf("\n");}free(input);return 0; }為什么使用strsep()分割字符串后會(huì)多出幾個(gè)"?-?" ?
原因是:如果輸入的串的有連續(xù)的多個(gè)字符屬于delim,strtok會(huì)返回NULL,而strsep會(huì)返回空串 ""。如果想用strsep函數(shù)分割字符串必須進(jìn)行返回值是否是空串的判斷。
?
使用strtok_r()完成分割
strtok是一個(gè)線程不安全的函數(shù),因?yàn)樗褂昧遂o態(tài)分配的空間來(lái)存儲(chǔ)被分割的字符串位置,線程安全的函數(shù)是strtok_r()。
char *strtok_r(char *str, const char *delim, char **saveptr);strtok_r函數(shù)是strtok函數(shù)的可重入版本。str為要分解的字符串,delim為分隔符字符串。char **saveptr參數(shù)是一個(gè)指向char *的指針變量,用來(lái)在strtok_r內(nèi)部保存切分時(shí)的上下文,以應(yīng)對(duì)連續(xù)調(diào)用分解相同源字符串。
第一次調(diào)用strtok_r時(shí),str參數(shù)必須指向待提取的字符串,saveptr參數(shù)的值可以忽略。連續(xù)調(diào)用時(shí),str賦值為NULL,saveptr為上次調(diào)用后返回的值,不要修改。一系列不同的字符串可能會(huì)同時(shí)連續(xù)調(diào)用strtok_r進(jìn)行提取,要為不同的調(diào)用傳遞不同的saveptr參數(shù)。
strtok_r實(shí)際上就是將strtok內(nèi)部隱式保存的this指針,以參數(shù)的形式與函數(shù)外部進(jìn)行交互。由調(diào)用者進(jìn)行傳遞、保存甚至是修改。需要調(diào)用者在連續(xù)切分相同源字符串時(shí),除了將str參數(shù)賦值為NULL,還要傳遞上次切分時(shí)保存下的saveptr。
#include <stdio.h> #include <stdlib.h> #include <string.h> //char *strtok_r(char *str, const char *delim, char **saveptr); int main() {char *Src = "Can I help you";char Buffer[100];char *delim = " ";char *saveptr = NULL;char *input = NULL;strncpy(Buffer, Src, sizeof(Buffer) - 1);input = Buffer;while(NULL != ( input = strtok_r( input, delim, &saveptr))){printf("input[%s] saveptr[%s]\n", input,saveptr);input = NULL;}return 0; }?
實(shí)現(xiàn)字符串分割
以上函數(shù)都會(huì)改變?cè)醋址?#xff0c;所以在完成split函數(shù)功能時(shí),要先復(fù)制一個(gè)副本,對(duì)副本進(jìn)行分割后返回相應(yīng)的值才是正確的思路。
#include <iostream> #include <vector> #include <cstring>using namespace std;namespace tyler { //strtok版本 //char *strtok(char s[], const char *delim);vector <string> stringsplit(const string &str, const char *delim){vector <std::string> strlist;int size = str.size();char *input = new char[size+1];strcpy(input, str.c_str());char *token = std::strtok(input, delim);while (token != NULL) {strlist.push_back(token);token = std::strtok(NULL, delim);}delete []input;return strlist;}//另一種寫法 //for(token = strtok(input, delim); token != NULL; token = strtok(NULL, delim)) //{ //}//strsep版本 //char *strsep(char **stringp, const char *delim);vector <string> stringsplit1(const string &str, const char *delim){vector <std::string> strlist;char *p = const_cast<char*>(str.c_str());char *input = strdup(p); //strdup()在內(nèi)部調(diào)用了malloc()為變量分配內(nèi)存,不需要使用返回的字符串時(shí),需要用free()釋放相應(yīng)的內(nèi)存空間,否則會(huì)造成內(nèi)存泄漏。char *token = strsep(&input, delim);while (token != NULL) {if(strcmp(token, "") == 0)token = strsep(&input, delim);else{strlist.push_back(token);token = strsep(&input, delim);}}free(input);return strlist;}//strtok_r版本 //char *strtok_r(char *str, const char *delim, char **saveptr);vector <string> stringsplit2(const string &str, const char *delim){vector <std::string> strlist;char *saveptr = NULL;char *p = const_cast<char*>(str.c_str());char *input = strdup(p); //strdup()在內(nèi)部調(diào)用了malloc()為變量分配內(nèi)存,不需要使用返回的字符串時(shí),需要用free()釋放相應(yīng)的內(nèi)存空間,否則會(huì)造成內(nèi)存泄漏。while(NULL != ( input = strtok_r( input, delim, &saveptr) )){//printf("input[%s] saveptr[%s]\n",input,saveptr);strlist.push_back(input);input = NULL;}free(input);return strlist;} }int main() {string str = "hello, world! welcome to china!";cout << str <<endl;vector<string> asd = tyler::stringsplit2(str, " ,!");cout << "StringList:";for(int i = 0; i < asd.size(); ++i){cout << "[" << asd[i] << "]";}cout <<endl;cout << "String:" << str <<endl;return 0; }?
參考:
https://baike.baidu.com/item/strtok_r
https://blog.csdn.net/yafeng_jiang/article/details/7109285
https://www.cnblogs.com/carsonzhu/p/5859552.html
https://blog.csdn.net/zhouzhenhe2008/article/details/74011399
總結(jié)
以上是生活随笔為你收集整理的C++实现字符串分割函数split()的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 内存对齐详解
- 下一篇: C++ unordered_map 使用