TAG: STL
| 一般來(lái)說(shuō),在處理字符串的時(shí)候通常會(huì )用到如下一些函數/方法:length、substring、find、charAt、 toLowerCase、toUpperCase、trim、equalsIgnoreCase、startsWith、endsWith、 parseInt、toString、split等。 如果使用STL中的std::string,它已經(jīng)提供了如下一些比較有用的方法:
關(guān)于std::string的其它方法,請參閱它的文檔(在MSDN中可以找到)。 很容易發(fā)現,std::string并沒(méi)有提供所有需要方法。所以,需要用STL提供了算法庫、字符串流以及現存的std::string的方法來(lái)實(shí)現它們。 ※ 將字符串轉換為大寫(xiě)/小寫(xiě) std::transform(str.begin(), str.end(), str.begin(), tolower); std::transform(str.begin(), str.end(), str.begin(), toupper); ※ 去掉字符串兩端的空格 1) 去掉左邊的空格 str.erase(0, str.find_first_not_of(" \\t\\n\\r")); 2) 去掉右邊的空格 str.erase(str.find_last_not_of(" \\t\\n\\r") + 1); 3) 去掉兩邊的空格 str.erase(0, str.find_first_not_of(" \\t\\n\\r")).erase(str.find_last_not_of(" \\t\\n\\r") + 1); ※ 忽略大小寫(xiě)比較字符串 這一功能的實(shí)現比較簡(jiǎn)單,只需要先將用于比較的兩個(gè)字符串各自拷貝一個(gè)復本,并將這兩個(gè)復本轉換為小寫(xiě),然后比較轉換為小寫(xiě)之后的兩個(gè)字符串即可。 ※ StartsWith和EndsWith 1) StartsWith str.find(substr) == 0; 如果返回值為true,則str是以substr開(kāi)始的 2) EndsWith str.rfind(substr) == (str.length() - substr.length()); 如果返回值為true,則str是以substr結束的 還有另一個(gè)方法可以實(shí)現這兩個(gè)函數。就是將str從頭/尾截取substr長(cháng)度的子串,再將這個(gè)子串也substr進(jìn)行比較。不過(guò)這種方法需要判斷str的長(cháng)度是否足夠,所以建議用find和rfind來(lái)實(shí)現。 ※ 從字符串解析出int和bool等類(lèi)型的值 說(shuō)到將字符串解析成int,首先想到的一定是atoi、atol等C函數。如果用C++來(lái)完成這些工具函數,那就要用到std::istringstream。 除了解析bool值之外,下面這個(gè)函數可以解析大部分的類(lèi)型的數值: template<class T> parseString(const std::string& str) { T value; std::istringstream iss(str); iss >> value; return value; } 上面這個(gè)模板可以將0解析成bool值false,將非0解析成treu。但它不能將字符串"false"解析成false,將"true"解析成true。因此要用一個(gè)特別的函數來(lái)解析bool型的值: template<bool> bool parseString(const std::string& str) { bool value; std::istringstream iss(str); iss >> boolalpha >> value; return value; } 上面的函數中,向輸入流傳入一個(gè)std::boolalpha標記,輸入流就能認識字符形式的"true"和"false"了。 使用與之類(lèi)似的辦法解析十六進(jìn)制字符串,需要傳入的標記是std::hex: template<class T> parseHexString(const std::string& str) { T value; std::istringstream iss(str); iss >> hex >> value; return value; } ※ 將各種數值類(lèi)型轉換成字符串(toString) 與解析字符串類(lèi)似,使用std::ostringstream來(lái)將各種數值類(lèi)型的數值轉換成字符串,與上面對應的3個(gè)函數如下: template<class T> std::string toString(const T& value) { std::ostringstream oss; oss << value; return oss.str(); } string toString(const bool& value) { ostringstream oss; oss << boolalpha << value; return oss.str(); } template<class T> std::string toHexString(const T& value, int width) { std::ostringstream oss; oss << hex; if (width > 0) { oss << setw(width) << setfill('0'); } oss << value; return oss.str(); } 注意到上面函數中用到的setw和setfill沒(méi)有?它們也是一種標記,使用的時(shí)候需要一個(gè)參數。std::setw規定了向流輸出的內容占用的寬 度,如果輸出內容的寬度不夠,默認就用空格填位。std::setfill則是用來(lái)設置占位符。如果還需要控制輸出內容的對齊方式,可以使用std:: left和std::right來(lái)實(shí)現。 ※ 拆分字符串和Tokenizer 拆分字符串恐怕得用Tokenizer來(lái)實(shí)現。C提供了strtok來(lái)實(shí)現Tokenizer,在STL中,用std::string的find_first_of和find_first_not_of來(lái)實(shí)現。下面就是Tokenizer類(lèi)的nextToken方法: bool Tokenizer::nextToken(const std::string& delimiters) { // find the start character of the next token. size_t i = m_String.find_first_not_of(delimiters, m_Offset); if (i == string::npos) { m_Offset = m_String.length(); return false; } // find the end of the token. size_t j = m_String.find_first_of(delimiters, i); if (j == string::npos) { m_Token = m_String.substr(i); m_Offset = m_String.length(); return true; } // to intercept the token and save current position m_Token = m_String.substr(i, j - i); m_Offset = j; return true; } ※ 源代碼 最后,關(guān)于上述的一些方法,都已經(jīng)實(shí)現在strutil.h和strutil.cpp中,所以現在附上這兩個(gè)文件的內容: √Header file: strutil.h //////////////////////////////////////////////////////////////////////////////// // // Utilities for std::string // defined in namespace strutil // by James Fancy // //////////////////////////////////////////////////////////////////////////////// #pragma once #include <string> #include <vector> #include <sstream> #include <iomanip> // declaration namespace strutil { std::string trimLeft(const std::string& str); std::string trimRight(const std::string& str); std::string trim(const std::string& str); std::string toLower(const std::string& str); std::string toUpper(const std::string& str); bool startsWith(const std::string& str, const std::string& substr); bool endsWith(const std::string& str, const std::string& substr); bool equalsIgnoreCase(const std::string& str1, const std::string& str2); template<class T> T parseString(const std::string& str); template<class T> T parseHexString(const std::string& str); template<bool> bool parseString(const std::string& str); template<class T> std::string toString(const T& value); template<class T> std::string toHexString(const T& value, int width = 0); std::string toString(const bool& value); std::vector<std::string> split(const std::string& str, const std::string& delimiters); } // Tokenizer class namespace strutil { class Tokenizer { public: static const std::string DEFAULT_DELIMITERS; Tokenizer(const std::string& str); Tokenizer(const std::string& str, const std::string& delimiters); bool nextToken(); bool nextToken(const std::string& delimiters); const std::string getToken() const; /** * to reset the tokenizer. After reset it, the tokenizer can get * the tokens from the first token. */ void reset(); protected: size_t m_Offset; const std::string m_String; std::string m_Token; std::string m_Delimiters; }; } // implementation of template functions namespace strutil { template<class T> T parseString(const std::string& str) { T value; std::istringstream iss(str); iss >> value; return value; } template<class T> T parseHexString(const std::string& str) { T value; std::istringstream iss(str); iss >> hex >> value; return value; } template<class T> std::string toString(const T& value) { std::ostringstream oss; oss << value; return oss.str(); } template<class T> std::string toHexString(const T& value, int width) { std::ostringstream oss; oss << hex; if (width > 0) { oss << setw(width) << setfill('0'); } oss << value; return oss.str(); } } √Source file: strutil.cpp //////////////////////////////////////////////////////////////////////////////// // // Utilities for std::string // defined in namespace strutil // by James Fancy // //////////////////////////////////////////////////////////////////////////////// #include "strutil.h" #include <algorithm> namespace strutil { using namespace std; string trimLeft(const string& str) { string t = str; t.erase(0, t.find_first_not_of(" \\t\\n\\r")); return t; } string trimRight(const string& str) { string t = str; t.erase(t.find_last_not_of(" \\t\\n\\r") + 1); return t; } string trim(const string& str) { string t = str; t.erase(0, t.find_first_not_of(" \\t\\n\\r")); t.erase(t.find_last_not_of(" \\t\\n\\r") + 1); return t; } string toLower(const string& str) { string t = str; transform(t.begin(), t.end(), t.begin(), tolower); return t; } string toUpper(const string& str) { string t = str; transform(t.begin(), t.end(), t.begin(), toupper); return t; } bool startsWith(const string& str, const string& substr) { return str.find(substr) == 0; } bool endsWith(const string& str, const string& substr) { return str.rfind(substr) == (str.length() - substr.length()); } bool equalsIgnoreCase(const string& str1, const string& str2) { return toLower(str1) == toLower(str2); } template<bool> bool parseString(const std::string& str) { bool value; std::istringstream iss(str); iss >> boolalpha >> value; return value; } string toString(const bool& value) { ostringstream oss; oss << boolalpha << value; return oss.str(); } vector<string> split(const string& str, const string& delimiters) { vector<string> ss; Tokenizer tokenizer(str, delimiters); while (tokenizer.nextToken()) { ss.push_back(tokenizer.getToken()); } return ss; } } namespace strutil { const string Tokenizer::DEFAULT_DELIMITERS(" "); Tokenizer::Tokenizer(const std::string& str) : m_String(str), m_Offset(0), m_Delimiters(DEFAULT_DELIMITERS) {} Tokenizer::Tokenizer(const std::string& str, const std::string& delimiters) : m_String(str), m_Offset(0), m_Delimiters(delimiters) {} bool Tokenizer::nextToken() { return nextToken(m_Delimiters); } bool Tokenizer::nextToken(const std::string& delimiters) { // find the start charater of the next token. size_t i = m_String.find_first_not_of(delimiters, m_Offset); if (i == string::npos) { m_Offset = m_String.length(); return false; } // find the end of the token. size_t j = m_String.find_first_of(delimiters, i); if (j == string::npos) { m_Token = m_String.substr(i); m_Offset = m_String.length(); return true; } // to intercept the token and save current position m_Token = m_String.substr(i, j - i); m_Offset = j; return true; } const string Tokenizer::getToken() const { return m_Token; } void Tokenizer::reset() { m_Offset = 0; } } |


