程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> std string使用

std string使用

編輯:C++入門知識

用 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

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved