std::string的工具函式

科技小先鋒發表於2017-11-14

一般來說,在處理字串的時候通常會用到如下一些函式/方法:length、substring、find、charAt、toLowerCase、toUpperCase、trim、equalsIgnoreCase、startsWith、endsWith、parseInt、toString、split等。

如果使用STL中的std::string,它已經提供瞭如下一些比較有用的方法:

length(),取得字串的長度。
substr(),從字串中取出一個子串。
at()/operator [],取得字串中指定位置的字元。
find/rfind(),從前往後/從後往前在字串中查詢一個子串的位置。
find_first_of(),在字串中找到第一個在指定字符集中的字元位置。
find_first_not_of(),在字串中找到第一次人不在指定字符集中的字元位置。
find_last_of(),在字串中找到最後一個在指定字符集中的字元位置。
find_last_not_of(),在字串中找到最後一個不在字符集中的字元位置。

  關於std::string的其它方法,請參閱它的文件(在MSDN中可以找到)。

  很容易發現,std::string並沒有提供所有需要方法。所以,需要用STL提供了演算法庫、字串流以及現存的std::string的方法來實現它們。

※ 將字串轉換為大寫/小寫

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);

※ 忽略大小寫比較字串

  這一功能的實現比較簡單,只需要先將用於比較的兩個字串各自拷貝一個複本,並將這兩個複本轉換為小寫,然後比較轉換為小寫之後的兩個字串即可。

※ StartsWith和EndsWith

1) StartsWith

str.find(substr) == 0;

如果返回值為true,則str是以substr開始的

2) EndsWith

str.rfind(substr) == (str.length()  substr.length());

如果返回值為true,則str是以substr結束的

  還有另一個方法可以實現這兩個函式。就是將str從頭/尾擷取substr長度的子串,再將這個子串也substr進行比較。不過這種方法需要判斷str的長度是否足夠,所以建議用find和rfind來實現。

※ 從字串解析出int和bool等型別的值

  說到將字串解析成int,首先想到的一定是atoi、atol等C函式。如果用C++來完成這些工具函式,那就要用到std::istringstream。

  除了解析bool值之外,下面這個函式可以解析大部分的型別的數值:

template<class T> parseString(const std::string& str) {

T value;

std::istringstream iss(str);

iss 
>> value;
return value;

}

  上面這個模板可以將0解析成bool值false,將非0解析成treu。但它不能將字串”false”解析成false,將”true”解析成true。因此要用一個特別的函式來解析bool型的值:

template<bool>
bool parseString(const std::string& str) {
bool value;

std::istringstream iss(str);

iss 
>> boolalpha >> value;
return value;

}

  上面的函式中,向輸入流傳入一個std::boolalpha標記,輸入流就能認識字元形式的”true”和”false”了。

  使用與之類似的辦法解析十六進位制字串,需要傳入的標記是std::hex:

template<class T> parseHexString(const std::string& str) {

T value;

std::istringstream iss(str);

iss 
>> hex >> value;
return value;

}

※ 將各種數值型別轉換成字串(toString)

  與解析字串類似,使用std::ostringstream來將各種數值型別的數值轉換成字串,與上面對應的3個函式如下:

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沒有?它們也是一種標記,使用的時候需要一個引數。std::setw規定了向流輸出的內容佔用的寬度,如果輸出內容的寬度不夠,預設就用空格填位。std::setfill則是用來設定佔位符。如果還需要控制輸出內容的對齊方式,可以使用std::left和std::right來實現。

※ 拆分字串和Tokenizer

  拆分字串恐怕得用Tokenizer來實現。C提供了strtok來實現Tokenizer,在STL中,用std::string的find_first_of和find_first_not_of來實現。下面就是Tokenizer類的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;

}

※ 原始碼

  最後,關於上述的一些方法,都已經實現在strutil.h和strutil.cpp中,所以現在附上這兩個檔案的內容:

√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;

}


}

 

本文轉自邊城__ 51CTO部落格,原文連結:http://blog.51cto.com/jamesfancy/843209,如需轉載請自行聯絡原作者


相關文章