C++字符串自制常用工具函數(shù)(格式化組裝描姚、各類型轉(zhuǎn)字符串、拆分數(shù)組戈次、替換子串轩勘、去除字符、大小寫轉(zhuǎn)換)

字符串格式化組裝通用函數(shù)

C++對字符串組裝沒有一個很直接好用的函數(shù)怯邪,這里利用C的snprintf()函數(shù)绊寻,提供一個可用的函數(shù):

template<typename ... Args>
std::string stringFormat(const std::string& format, Args ... args ) {
    size_t size = (size_t)snprintf( NULL, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
#ifdef C11
    std::unique_ptr<char> buf(new char[size]);
#else
    std::auto_ptr<char> buf(new char[size]);
#endif
    snprintf( buf.get(), size, format.c_str(), args ... );
    return std::string(buf.get(), size - 1); // We don't want the '\0' inside
}

這里的stringFormat函數(shù)是一個模板函數(shù),可以接受多種形式的格式化組裝悬秉,也就是可以拼接int澄步、float、long和泌、string等各種類型的變量村缸。

之所以這里的模板參數(shù)和函數(shù)的最后一個參數(shù)都是省略號,是C允許的一種參數(shù)表示形式允跑,必須放在最后一個王凑,且必須前面有確定的參數(shù),它表示后續(xù)的參數(shù)個數(shù)不定聋丝。這里配合模板索烹,也就是參數(shù)的個數(shù)和類型都不定了。所以我們可以用來組裝任何類型的變量弱睦。

snprintf()也是C的一個函數(shù)百姓,用法如下:

int snprintf(char *str, int n, char * format [, argument, ...]);

參數(shù)中:

  • str:目的地址,用來存組裝后的char數(shù)組地址况木;
  • n:保留的字符個數(shù)(不包含最后的'\0')垒拢,這里需要注意,不管后面組裝了多少字符火惊,最終結(jié)果只會保留這里的n個字符求类,再在結(jié)尾加上一個'\0'表示結(jié)束;
  • format:格式char數(shù)組屹耐,也就是我們常用的類似“hello %s”這樣的待組裝格式了尸疆;
  • argument...:不定個數(shù)的參數(shù),用來適配格式char數(shù)組需要的變量。

返回值:返回組裝后的本應(yīng)有的char數(shù)組長度寿弱,不包括最后的'\0'犯眠。注意并不是n的數(shù)值,否則這個返回沒有意義症革,這里返回的是本應(yīng)有的char數(shù)組長度筐咧,也就是format組裝好變量后的全長,而n相當(dāng)于是設(shè)置要截取前面的多少個字符賦給str噪矛。

這樣就清楚了量蕊,這里我們的目的地址放了NULL,保留的字符個數(shù)又是0摩疑,所以沒有要截取保留的str危融,只是單純計算一下組裝所需要的長度,因為函數(shù)返回不包括'\0'雷袋,所以這里要加一。

然后我們創(chuàng)建一個char類型的數(shù)組辞居,用算好的長度去初始化楷怒。根據(jù)編譯器的C++版本不同,使用唯一指針或者自動指針瓦灶。唯一指針是C++11的特性鸠删,同一對象只能被一個unique_ptr來擁有,禁止進行拷貝構(gòu)造和賦值構(gòu)造操作贼陶。當(dāng)unique_ptr指針對象離開其作用域時刃泡,生命期結(jié)束,自動使用內(nèi)部給定的刪除器(deleter)delete所指向的對象碉怔。所以函數(shù)結(jié)束后烘贴,其申請的資源會自動刪除。

創(chuàng)建好char數(shù)組后撮胧,我們就進行實際的組裝桨踪,再次使用snprintf函數(shù),這次我們知道了需要的長度就是我們前面計算出來的長度芹啥,將前面創(chuàng)建的char數(shù)組放到目的char數(shù)組的參數(shù)位置锻离,進行組裝。前面要計算一次長度的原因就是因為我們并不知道實際使用的時候會組裝多長的字符串墓怀,如果隨意創(chuàng)建一個長度的char數(shù)組汽纠,要么浪費,要么不夠傀履。

最后虱朵,我們用組裝后的結(jié)果char數(shù)組來初始化字符串,并返回,這里只要前面的實際字符卧秘,不要最后的'\0'呢袱。

數(shù)值類型轉(zhuǎn)字符串

C++11以前沒有直接的數(shù)值類型轉(zhuǎn)字符串的函數(shù),這里提供一些:

std::string itoString(int i) {
    char buf[30] = {0};
    sprintf(buf, "%d", i);
    return std::string(buf);
}

std::string ltoString(long i) {
    char buf[30] = {0};
    sprintf(buf, "%ld", i);
    return std::string(buf);
}

std::string lltoString(long long i) {
    char buf[30] = {0};
    sprintf(buf, "%lld", i);
    return std::string(buf);
}

其實都是利用sprintf函數(shù)來做格式化翅敌,將數(shù)值類型轉(zhuǎn)為char數(shù)組羞福,再轉(zhuǎn)為string類型返回。

各類型轉(zhuǎn)String

還有一種更通用的轉(zhuǎn)String 的方法:

template <class T>
static string ToString(const T& tmp)
{
    stringstream ss;
    ss << tmp;
    return ss.str();
}

做成模板函數(shù)蚯涮,利用stringstream治专,來接收各種類型的參數(shù),返回字符串遭顶。

字符串根據(jù)特定字符拆分成數(shù)組通用函數(shù)

split是其他語言中將字符串轉(zhuǎn)化為數(shù)組的常用函數(shù)张峰,C++中卻沒有,這里提供一個通用函數(shù)棒旗,可以將字符串根據(jù)特定字符拆分成數(shù)組:

#include <string>
#include <vector>

using std::string;
using std::vector;

vector<string> split(const string &str, const string &separtor) {
    size_t begin = 0, end = 0;
    vector<string> result;

    while (true) {
        end = str.find(separtor, begin);
        if (end == string::npos) {
            result.push_back(str.substr(begin));
            break;
        } else {
            result.push_back(str.substr(begin, end-begin));
            begin = end + separtor.size();
        }
    }
    return result;
}

函數(shù)接收要拆分的字符串和指定的分隔符字符串喘批,都是const形式,因為不想對其做更改铣揉。返回拆分好的數(shù)組饶深,也就是string類型的vector。

初始化需要的變量后逛拱,在無限循環(huán)中敌厘,使用string的find函數(shù)來找分隔符出現(xiàn)的位置,第二個參數(shù)是指開始找的位置朽合,這里一開始是0俱两。find函數(shù)會返回第一次找到的位置,如果找不到曹步,會返回string::npos宪彩,這里的npos一般是一個size_t的最大值,在字符串中就是字符串的最后位置箭窜。

所以下面如果是string::npos毯焕,那就表示在begin位置后找不到了,直接從begin開始截取子串直到字符串的最后位置磺樱,放到數(shù)組中去纳猫。

如果不是,說明找到了竹捉,因此從begin開始截取需要的長度芜辕,長度由end-begin計算出來。substr函數(shù)接受截取的開始位置和長度块差,長度默認為最大值侵续,也就是到直到字符串末尾倔丈。截取完后,再更新begin到分隔符后的位置状蜗,方便下一次尋找需五。

最后返回分割后的字符串。

替換字符串中某個子串

將字符串中某個子串全部替換為另一個子串:

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length();
     }
     return str;
}

做法就是不斷在字符串中找到要被替換的子串轧坎,得到位置后宏邮,用replace函數(shù)替換成目的子串,直到找不到為止缸血。注意該函數(shù)并沒有改變源字符串蜜氨,而是復(fù)制了實參,修改后返回捎泻。

去空格(或其他字符)

去除字符串中的空格飒炎,這個用上面的函數(shù)也能實現(xiàn),不過這相當(dāng)于是去除某種字符的通用函數(shù)了:

std::string Trim(const std::string& str, const char target = ' ') {
    string retStr = "";
    for (size_t i = 0, n = str.length(); i < n; ++i) {
        if (str[i] != target) {
            retStr += str[i];
        }
    }
    return retStr;
}

簡單的遍歷判斷笆豁,默認為去除空格郎汪,也可以去除其他的字符。

大小寫轉(zhuǎn)換

將字符串中的字母全部轉(zhuǎn)為大寫或者全部轉(zhuǎn)為小寫:

void toUpperCase(string &s) {
    for (string::iterator it = s.begin(); it != s.end(); it++) {
        char c = (char)std::toupper(*it);
        *it = c;
    }
}

void toLowerCase(string &s) {
    for (string::iterator it = s.begin(); it != s.end(); it++) {
        char c = (char)std::tolower(*it);
        *it = c;
    }
}

利用toupper/tolower函數(shù)渔呵,用迭代器遍歷每個字符怒竿,進行修改。這里改的是原字符串扩氢,不需要返回新字符串。

toupper/tolower函數(shù)源碼本身只會對屬于字母的字符進行修改爷辱,非字母字符會原樣返回录豺,所以不需要擔(dān)心字符串中包含非字母的字符。


查看作者首頁

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饭弓,一起剝皮案震驚了整個濱河市双饥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弟断,老刑警劉巖咏花,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異阀趴,居然都是意外死亡昏翰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門刘急,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棚菊,“玉大人,你說我怎么就攤上這事叔汁⊥城螅” “怎么了检碗?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長码邻。 經(jīng)常有香客問我折剃,道長,這世上最難降的妖魔是什么像屋? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任怕犁,我火速辦了婚禮,結(jié)果婚禮上开睡,老公的妹妹穿的比我還像新娘因苹。我一直安慰自己,他們只是感情好篇恒,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布扶檐。 她就那樣靜靜地躺著,像睡著了一般胁艰。 火紅的嫁衣襯著肌膚如雪款筑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天腾么,我揣著相機與錄音奈梳,去河邊找鬼。 笑死解虱,一個胖子當(dāng)著我的面吹牛攘须,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播殴泰,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼于宙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悍汛?” 一聲冷哼從身側(cè)響起捞魁,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎离咐,沒想到半個月后谱俭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡宵蛀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年昆著,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糖埋。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡宣吱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞳别,到底是詐尸還是另有隱情征候,我是刑警寧澤杭攻,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站疤坝,受9級特大地震影響兆解,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跑揉,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一锅睛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧历谍,春花似錦现拒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脱衙,卻和暖如春侥猬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捐韩。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工退唠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荤胁。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓瞧预,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仅政。 傳聞我的和親對象是個殘疾皇子松蒜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353