用 string來代替char * 數組,使用sort排序算法來排序,用unique 函數來去重
1、Define
string s1 = "hello";
string s2 = "world";
string s3 = s1 + "," + s2 +"!\n";
2、append
s1 += ",shanshan\n";
3、Compare
if(s1 == s2)
.....
else if(s1 == "hello")
.....
4、 string 重載了許多操作符,包括 +, +=, <, =, , [], <<, >>等,正式這些操作符,對字符串操作非常方便
#include <string>
#include <iostream>
using namespace std;
int main(){
string strinfo="Please input your name:";
cout << strinfo ;
cin >> strinfo;
if( strinfo == "winter" )
cout << "you are winter!"<<endl;
else if( strinfo != "wende" )
cout << "you are not wende!"<<endl;
else if( strinfo < "winter")
cout << "your name should be ahead of winter"<<endl;
else
cout << "your name should be after of winter"<<endl;
strinfo += " , Welcome to China!";
cout << strinfo<<endl;
cout <<"Your name is :"<<endl;
string strtmp = "How are you? " + strinfo;
for(int i = 0 ; i < strtmp.size(); i ++)
cout<<strtmp[i];
return 0;
} 5、find函數
由於查找是使用最為頻繁的功能之一,string 提供了非常豐富的查找函數。其列表如下: 函數名 描述
find 查找
rfind 反向查找
find_first_of 查找包含子串中的任何字符,返回第一個位置
find_first_not_of 查找不包含子串中的任何字符,返回第一個位置
find_last_of 查找包含子串中的任何字符,返回最後一個位置
find_last_not_of 查找不包含子串中的任何字符,返回最後一個位置
以上函數都是被重載了4次,以下是以find_first_of 函數為例說明他們的參數,其他函數和其參數一樣,也就是說總共有24個函數:
size_type find_first_of(const basic_string& s, size_type pos = 0)
size_type find_first_of(const charT* s, size_type pos, size_type n)
size_type find_first_of(const charT* s, size_type pos = 0)
size_type find_first_of(charT c, size_type pos = 0)
所有的查找函數都返回一個size_type類型,這個返回值一般都是所找到字符串的位置,如果沒有找到,則返回string::npos。
其實string::npos表示的是-1。即沒找到就返回-1。例子如下:
#include <string>
#include <iostream>
using namespace std;
int main(){
string strinfo=" //*---Hello Word!......------";
string strset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int first = strinfo.find_first_of(strset);
if(first == string::npos) {
cout<<"not find any characters"<<endl;
return -1;
}
int last = strinfo.find_last_of(strset);
if(last == string::npos) {
cout<<"not find any characters"<<endl;
return -1;
}
cout << strinfo.substr(first, last - first + 1)<<endl;//string.substr是子串
return 0;
}
6、insert函數, replace函數和erase函數
string只是提供了按照位置和區間的replace函數,而不能用一個string字串來替換指定string中的另一個字串。
例子:
#include <string>
#include <iostream>
using namespace std;
int main() {
string strinfo="This is Winter, Winter is a programmer. Do you know Winter?";
cout<<"Orign string is :\n"<<strinfo<<endl;
string_replace(strinfo, "Winter", "wende");
cout<<"After replace Winter with wende, the string is :\n"<<strinfo<<endl;
return 0;
}
string.erase(pos,srclen);//srclen是刪除的長度
string.insert(pos,strdst); //pos是定位,strdst是插入的函數
void string_replace(string & strBig, const string & strsrc, const string &strdst) {
string::size_type pos=0;
string::size_type srclen=strsrc.size();
string::size_type dstlen=strdst.size();
while( (pos=strBig.find(strsrc, pos)) != string::npos){
strBig.erase(pos, srclen);
strBig.insert(pos, strdst);
pos += dstlen;
}
}
相關鏈接:http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString
7、切割字符串
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string text = "big|dog|china|sonic|free";
stringstream ss(text);
string sub_str;
while(getline(ss,sub_str,'|')) //以|為間隔分割test的內容
cout << sub_str << endl;
return 0;
}
輸出如下:
big
dog
china
sonic
free
8、構造函數和析構函數
string s 生成一個空字符串S
string s(str) Copy構造函數,生成字符串Str的一個復制品
string s(str,stridx) 將字符串Str內始於位置Stridx的部分,當作字符串S的初值
string s(str,stridx,strlen) 將字符串Str內始於位置Stridx且長度為strlen的部分,當作字符串S的初值string s(cstr) 以C-String cstr作為S的初值
string s(num,c) 生成一個字符串,包含Num個C字符
string s(beg,end) 以區間[beg,end]內的字符作為s初值
s.~string() 銷毀所有字符,釋放內存
注意:
std::string s('x');//error
std::string s(1,'x'); //ok,create a string that has one charactor 'x'
9、substr(string.substr的方法)
(1)參數
start:Number -- 一個整數,指示 my_str 中用於創建子字符串的第一個字符的位置。如果 start 為一個負數,則起始位置從字符串的結尾開始確定,其中 -1 表示最後一個字符。
length:Number -- 要創建的子字符串中的字符數。如果沒有指定 length,則子字符串包括從字符串開頭到字符串結尾的所有字符。
(2)返回
String -- 指定字符串的子字符串。
(3)示例
下面的示例創建一個新字符串 my_str,並使用 substr() 返回該字符串中的第二個單詞;首先,使用正的 start 參數,然後使用負的 start 參數:
var my_str:String = new String("Hello world");
var mySubstring:String = new String();
mySubstring = my_str.substr(6,5);
trace(mySubstring); // 輸出:world
mySubstring = my_str.substr(-5,5);
trace(mySubstring); // 輸出:world
toupper, tolower
地球人都知道 C++ 的 string 沒有 toupper ,好在這不是個大問題,因為我們有 STL 算法:
string s("heLLo");
transform(s.begin(), s.end(), s.begin(), toupper);
cout << s << endl;
transform(s.begin(), s.end(), s.begin(), tolower);
cout << s << endl;
當然,我知道很多人希望的是 s.to_upper() ,但是對於一個這麼通用的 basic_string 來說,的確沒辦法把這些專有的方法放進來。如果你用 boost stringalgo ,那當然不在話下,你也就不需要讀這篇文章了。
------------------------------------------------------------------------
trim
我們還知道 string 沒有 trim ,不過自力更生也不困難,比 toupper 來的還要簡單:
string s(" hello ");
s.erase(0, s.find_first_not_of(" \n"));
cout << s << endl;
s.erase(s.find_last_not_of('' '') + 1);
cout << s << endl;
注意由於 find_first_not_of 和 find_last_not_of 都可以接受字符串,這個時候它們尋找該字符串中所有字符的 absence ,所以你可以一次 trim 掉多種字符。
-----------------------------------------------------------------------
erase
string 本身的 erase 還是不錯的,但是只能 erase 連續字符,如果要拿掉一個字符串裡面所有的某個字符呢?用 STL 的 erase + remove_if 就可以了,注意光 remove_if 是不行的。
string s(" hello, world. say bye ");
s.erase(remove_if(s.begin(),s.end(),
bind2nd(equal_to<char>(), '' '')),
s.end());
上面的這段會拿掉所有的空格,於是得到 hello,world.saybye。
-----------------------------------------------------------------------
replace
string 本身提供了 replace ,不過並不是面向字符串的,譬如我們最常用的把一個 substr 換成另一個 substr 的操作,就要做一點小組合:
string s("hello, world");
string sub("ello, ");
s.replace(s.find(sub), sub.size(), "appy ");
cout << s << endl;
輸出為 happy world。注意原來的那個 substr 和替換的 substr 並不一定要一樣長。
-----------------------------------------------------------------------
startwith, endwith
這兩個可真常用,不過如果你仔細看看 string 的接口,就會發現其實沒必要專門提供這兩個方法,已經有的接口可以干得很好:
string s("hello, world");
string head("hello");
string tail("ld");
bool startwith = s.compare(0, head.size(), head) == 0;
cout << boolalpha << startwith << endl;
bool endwith = s.compare(s.size() - tail.size(), tail.size(), tail) == 0;
cout << boolalpha << endwith << endl;
當然了,沒有 s.startwith("hello") 這樣方便。
------------------------------------------------------------------------
toint, todouble, tobool...
這也是老生常談了,無論是 C 的方法還是 C++ 的方法都可以,各有特色:
string s("123");
int i = atoi(s.c_str());
cout << i << endl;
int ii;
stringstream(s) >> ii;
cout << ii << endl;
string sd("12.3");
double d = atof(sd.c_str());
cout << d << endl;
double dd;
stringstream(sd) >> dd;
cout << dd << endl;
string sb("true");
bool b;
stringstream(sb) >> boolalpha >> b;
cout << boolalpha << b << endl;
C 的方法很簡潔,而且賦值與轉換在一句裡面完成,而 C++ 的方法很通用。
------------------------------------------------------------------------
split
這可是件麻煩事,我們最希望的是這樣一個接口: s.split(vect, '','') 。用 STL 算法來做有一定難度,我們可以從簡單的開始,如果分隔符是空格、tab 和回車之類,那麼這樣就夠了:
string s("hello world, bye.");
vector<string> vect;
vect.assign(
istream_iterator<string>(stringstream(s)),
istream_iterator<string>()
);
不過要注意,如果 s 很大,那麼會有效率上的隱憂,因為 stringstream 會 copy 一份 string 給自己用。
------------------------------------------------------------------------
concat
把一個裝有 string 的容器裡面所有的 string 連接起來,怎麼做?希望你不要說是 hand code 循環,這樣做不是更好?
vector<string> vect;
vect.push_back("hello");
vect.push_back(", ");
vect.push_back("world");
cout << accumulate(vect.begin(), vect.end(), string(""));
不過在效率上比較有優化余地。
-------------------------------------------------------------------------
reverse
其實我比較懷疑有什麼人需要真的去 reverse 一個 string ,不過做這件事情的確是很容易:
std::reverse(s.begin(), s.end());
上面是原地反轉的方法,如果需要反轉到別的 string 裡面,一樣簡單:
s1.assign(s.rbegin(), s.rend());
效率也相當理想。
-------------------------------------------------------------------------
解析文件擴展名
字數多點的寫法:
std::string filename("hello.exe");
std::string::size_type pos = filename.rfind(''.'');
std::string ext = filename.substr(pos == std::string::npos ? filename.length() : pos + 1);
不過兩行,合並成一行呢?也不是不可以:
std::string ext = filename.substr(filename.rfind(''.'') == std::string::npos ? filename.length() : filename.rfind(''.'') + 1);
我知道,rfind 執行了兩次。不過第一,你可以希望編譯器把它優化掉,其次,擴展名一般都很短,即便多執行一次,區別應該是相當微小。
GBK中文編碼和std::string的沖突問題
最近寫了一個按照分隔符拆分字符串的接口,
void PickUp(std::string &strDes,std::vector<std::string>
&vecData,const std::string sign=";" )
{
std::string::size_type fpos=0,bpos=0;
std::string strTemp;
while(bpos != std::string::npos && strDes.size())
{
bpos = strDes.find(sign,fpos);
strTemp = strDes.substr (fpos,bpos-fpos);
vecData.push_back (strTemp);
fpos = bpos+1;
}
}
開始用得挺舒服沒有出現問題,但是後來出現了一個新的需求又用到這個接口,但是分隔符不再是默認的";",而是換成了下劃線"_"。這時問題出現了:比如下代碼
int main() www.2cto.com
{
std::string strDes("開關_電視臺");
std::vector<std::string> vecTemp;
PickUp(strDes,vecTemp,"_");
system("pause");
return 0;
}
粗看可能看不出什麼問題,但是結果是錯誤的,仔細斷點跟蹤並網上查閱了相關資料,終於弄懂原因了。
std::string 的find函數是按照單字節查找對比的,而GBK 采用雙字節表示,總體編碼范圍為 0x8140-FEFE,首字節在 0x81-FE 之間,尾字節在 0x40-FE 之間
而開字的內存數據為e9 5f,臺字的內存數據為c5 5f,下劃線"_"的內存為5f,也就是說開字的尾字節和下劃線ascii"_"是一樣的,不行的是std::string 的find是采用單字節查找的,所以出現的結果是vecTemp的size()變成了4,其中包括兩個空的字符串,而不是預期的結果2;而之前沒有出問題是因為分隔符分號的緣故";",";"的ascii碼是小於0x40的。
所以解決此種問題的辦法就是分隔符應該去小於0x40也就是ascii碼小於64的,至於哪些小於64就需自己去查了
或者可以自己寫個單字節比較find算法.....
boost::tokenizer不錯
作者:zhongguoren666