C++ string 詳解

C++中針對C語言中處理字符串的難題,在標準庫中設計了string類,因此現在編程中涉及到字符串的處理,就可以直接使用string類了。

    之所以拋棄char*的字符串而選用C++標準程序庫中的string類,是因爲他和前者比較起來,不必擔心內存是否足夠、字符串長度等等,而且作爲一個類出現,他集成的操作函數足以完成我們大多數情況下(甚至是100%)的需要。我們可以用 =進行賦值操作,== 進行比較,+ 做串聯(是不是很簡單?)。我們儘可以把它看成是C++的基本數據類型。

  

首先,爲了在我們的程序中使用string類型,我們必須包含頭文件。如下:

   #include <string>//注意這裏不是string.h string.h是C字符串頭文件

 

1.聲明一個C++字符串

聲明一個字符串變量很簡單:

   string Str;

這樣我們就聲明瞭一個字符串變量,但既然是一個類,就有構造函數和析構函數。上面的聲明沒有傳入參數,所以就直接使用了string的默認的構造函數,這個函數所作的就是把Str初始化爲一個空字符串。String類的構造函數和析構函數如下:

a)    string s;  //生成一個空字符串s

b)    string s(str) //拷貝構造函數 生成str的複製品

c)    string s(str,stridx)//將字符串str內“始於位置stridx”的部分當作字符串的初值

d)    strings(str,stridx,strlen) //將字符串str內“始於stridx且長度頂多strlen”的部分作爲字符串的初值

e)    string s(cstr) //將C字符串作爲s的初值

f)    strings(chars,chars_len) //將C字符串前chars_len個字符作爲字符串s的初值。

g)    string s(num,c) //生成一個字符串,包含num個c字符

h)    string s(beg,end) //以區間beg;end(不包含end)內的字符作爲字符串s的初值

i)    s.~string() //銷燬所有字符,釋放內存

都很簡單,我就不解釋了。

2.字符串操作函數

   這裏是C++字符串的重點,我先把各種操作函數羅列出來,不喜歡把所有函數都看完的人可以在這裏找自己喜歡的函數,再到後面看他的詳細解釋。

a) =,assign()   //賦以新值

b) swap()   //交換兩個字符串的內容

c) +=,append(),push_back() //在尾部添加字符

d) insert() //插入字符

e) erase() //刪除字符

f) clear() //刪除全部字符

g) replace() //替換字符

h) + //串聯字符串

i)==,!=,<,<=,>,>=,compare()  //比較字符串

j) size(),length()  //返回字符數量

k) max_size() //返回字符的可能最大個數

l) empty()  //判斷字符串是否爲空

m) capacity() //返回重新分配之前的字符容量

n) reserve() //保留一定量內存以容納一定數量的字符

o) [ ], at() //存取單一字符

p) >>,getline() //從stream讀取某值

q) <<  //將謀值寫入stream

r) copy() //將某值賦值爲一個C_string

s) c_str() //將內容以C_string返回

t) data() //將內容以字符數組形式返回

u) substr() //返回某個子字符串

v)查找函數

w)begin() end() //提供類似STL的迭代器支持

x) rbegin() rend() //逆向迭代器

y) get_allocator() //返回配置器

下面詳細介紹:

2.1 C++字符串和C字符串的轉換

   C++提供的由C++字符串得到對應的C_string的方法是使用data()、c_str()和copy(),其中,data()以字符數組的形式返回字符串內容,但並不添加’\0’。c_str()返回一個以‘\0’結尾的字符數組,而copy()則把字符串的內容複製或寫入既有的c_string或字符數組內。C++字符串並不以’\0’結尾。我的建議是在程序中能使用C++字符串就使用,除非萬不得已不選用c_string。由於只是簡單介紹,詳細介紹掠過,誰想進一步瞭解使用中的注意事項可以給我留言(到我的收件箱)。我詳細解釋。

2.2 大小和容量函數

   一個C++字符串存在三種大小:a)現有的字符數,函數是size()和length(),他們等效。Empty()用來檢查字符串是否爲空。b)max_size() 這個大小是指當前C++字符串最多能包含的字符數,很可能和機器本身的限制或者字符串所在位置連續內存的大小有關係。我們一般情況下不用關心他,應該大小足夠我們用的。但是不夠用的話,會拋出length_error異常c)capacity()重新分配內存之前 string所能包含的最大字符數。這裏另一個需要指出的是reserve()函數,這個函數爲string重新分配內存。重新分配的大小由其參數決定,默認參數爲0,這時候會對string進行非強制性縮減。

 

還有必要再重複一下C++字符串和C字符串轉換的問題,許多人會遇到這樣的問題,自己做的程序要調用別人的函數、類什麼的(比如數據庫連接函數Connect(char*,char*)),但別人的函數參數用的是char*形式的,而我們知道,c_str()、data()返回的字符數組由該字符串擁有,所以是一種const char*,要想作爲上面提及的函數的參數,還必須拷貝到一個char*,而我們的原則是能不使用C字符串就不使用。那麼,這時候我們的處理方式是:如果此函數對參數(也就是char*)的內容不修改的話,我們可以這樣Connect((char*)UserID.c_str(),(char*)PassWD.c_str()),但是這時候是存在危險的,因爲這樣轉換後的字符串其實是可以修改的(有興趣地可以自己試一試),所以我強調除非函數調用的時候不對參數進行修改,否則必須拷貝到一個char*上去。當然,更穩妥的辦法是無論什麼情況都拷貝到一個char*上去。同時我們也祈禱現在仍然使用C字符串進行編程的高手們(說他們是高手一點兒也不爲過,也許在我們還穿開襠褲的時候他們就開始編程了,哈哈…)寫的函數都比較規範,那樣我們就不必進行強制轉換了。

 

2.3元素存取

   我們可以使用下標操作符[]和函數at()對元素包含的字符進行訪問。但是應該注意的是操作符[]並不檢查索引是否有效(有效索引0~str.length()),如果索引失效,會引起未定義的行爲。而at()會檢查,如果使用at()的時候索引無效,會拋出out_of_range異常。

   有一個例外不得不說,const string a;的操作符[]對索引值是a.length()仍然有效,其返回值是’\0’。其他的各種情況,a.length()索引都是無效的。舉例如下:

const string Cstr(“const string”);

string Str(“string”);

 

Str[3];    //ok

Str.at(3);  //ok

 

Str[100]; //未定義的行爲

Str.at(100);  //throw out_of_range

 

Str[Str.length()]  //未定義行爲

Cstr[Cstr.length()] //返回 ‘\0’

Str.at(Str.length());//throw out_of_range

Cstr.at(Cstr.length()) ////throwout_of_range

 

我不贊成類似於下面的引用或指針賦值:

char& r=s[2];

char* p= &s[3];

因爲一旦發生重新分配,r,p立即失效。避免的方法就是不使用。

 

2.4比較函數

   C++字符串支持常見的比較操作符(>,>=,<,<=,==,!=),甚至支持string與C-string的比較(如 str<”hello”)。在使用>,>=,<,<=這些操作符的時候是根據“當前字符特性”將字符按字典順序進行逐一得比較。字典排序靠前的字符小,比較的順序是從前向後比較,遇到不相等的字符就按這個位置上的兩個字符的比較結果確定兩個字符串的大小。同時,string(“aaaa”)   另一個功能強大的比較函數是成員函數compare()。他支持多參數處理,支持用索引值和長度定位子串來進行比較。他返回一個整數來表示比較結果,返回值意義如下:0-相等〉0-大於 <0-小於。舉例如下:

   string s(“abcd”);

  

   s.compare(“abcd”); //返回0

   s.compare(“dcba”); //返回一個小於0的值

   s.compare(“ab”); //返回大於0的值

  

s.compare(s); //相等

   s.compare(0,2,s,2,2); //用”ab”和”cd”進行比較 小於零

   s.compare(1,2,”bcx”,2); //用”bc”和”bc”比較。

怎麼樣?功能夠全的吧!什麼?還不能滿足你的胃口?好吧,那等着,後面有更個性化的比較算法。先給個提示,使用的是STL的比較算法。什麼?對STL一竅不通?靠,你重修吧!

 

2.5 更改內容

這在字符串的操作中佔了很大一部分。

 

 

首先講賦值,第一個賦值方法當然是使用操作符=,新值可以是string(如:s=ns) 、c_string(如:s=”gaint”)甚至單一字符(如:s=’j’)。還可以使用成員函數assign(),這個成員函數可以使你更靈活的對字符串賦值。還是舉例說明吧:

s.assign(str); //不說

s.assign(str,1,3);//如果str是”iamangel” 就是把”ama”賦給字符串

s.assign(str,2,string::npos);//把字符串str從索引值2開始到結尾賦給s

s.assign(“gaint”); //不說

s.assign(“nico”,5);//把’n’ ‘I’‘c’ ‘o’ ‘\0’賦給字符串

s.assign(5,’x’);//把五個x賦給字符串

把字符串清空的方法有三個:s=””;s.clear();s.erase();(我越來越覺得舉例比說話讓別人容易懂!)。

string提供了很多函數用於插入(insert)、刪除(erase)、替換(replace)、增加字符。

先說增加字符(這裏說的增加是在尾巴上),函數有 +=、append()、push_back()。舉例如下:

s+=str;//加個字符串

s+=”my name is jiayp”;//加個C字符串

s+=’a’;//加個字符

 

s.append(str);

s.append(str,1,3);//不解釋了同前面的函數參數assign的解釋

s.append(str,2,string::npos)//不解釋了

 

s.append(“my name is jiayp”);

s.append(“nico”,5);

s.append(5,’x’); 

 

    字符串操作是一個不小的主題,在標準C++中,string字符串類成爲一個標準,之所以拋棄char*的字符串而選用C++標準程序庫中的string類,是因爲他和前者比較起來,不必擔心內存是否足夠、字符串長度等等,而且作爲一個類出現,他集成的操作函數足以完成我們大多數情況下的需要.

 

 

 

 


C++ Strings(字符串)
--------------------------------------------------------------------------------

構造函數(Constructors)
語法:
string();
string( size_type length, char ch );
string( const char *str );
string( const char *str, size_type length );
string( string &str, size_type index, size_type length );
string( input_iterator start, input_iterator end );


字符串的構造函數創建一個新字符串,包括:

length爲長度的ch的拷貝(即lengthch
str爲初值 (長度任意),
index爲索引開始的子串,長度爲length, 或者
以從startend的元素爲初值.
例如,

   string str1( 5, 'c' );
    string str2( "Now is the time..." );
    string str3( str2, 11, 4 );
    cout << str1 << endl;
    cout << str2 << endl;
    cout << str3 << endl;

顯示

   ccccc
    Now is the time...
    time
  


--------------------------------------------------------------------------------

操作符(Operators)
語法:
==
>
<
>=
<=
!=
+
+=
[]


你可以用 ==, >, <, >=, <=, and !=比較字符串. 可以用 + 或者 += 操作符連接兩個字符串, 並且可以用[]獲取特定的字符.

相關主題:
at(), compare().
--------------------------------------------------------------------------------

添加文本(append)
語法:
basic_string &append( const basic_string &str );
basic_string &append( const char *str );
basic_string &append( const basic_string &str, size_type index, size_typelen );
basic_string &append( const char *str, size_type num );
basic_string &append( size_type num, char ch );
basic_string &append( input_iterator start, input_iterator end );


append() 函數可以完成以下工作:

在字符串的末尾添加str,
在字符串的末尾添加str的子串,子串以index索引開始,長度爲len
在字符串的末尾添加str中的num個字符,
在字符串的末尾添加num個字符ch,
在字符串的末尾添加以迭代器startend表示的字符序列.
例如以下代碼:

   string str = "Hello World";
    str.append( 10, '!' );
    cout << str << endl;

顯示

   Hello World!!!!!!!!!!

相關主題:
+
操作符
--------------------------------------------------------------------------------

賦值(assign)
語法:
basic_string &assign( const basic_string &str );
basic_string &assign( const char *str );
basic_string &assign( const char *str, size_type num );
basic_string &assign( const basic_string &str, size_type index,size_type len );
basic_string &assign( size_type num, char ch );


函數以下列方式賦值:

str爲字符串賦值,
str的開始num個字符爲字符串賦值,
str的子串爲字符串賦值,子串以index索引開始,長度爲len
num個字符ch爲字符串賦值.
例如以下代碼:

   string str1, str2 = "War and Peace";
    str1.assign( str2, 4, 3 );
    cout << str1 << endl;

顯示

   and
  


--------------------------------------------------------------------------------

at
語法:
reference at( size_type index );


at()函數返回一個引用,指向在index位置的字符. 如果index不在字符串範圍內, at() 將報告"out of range"錯誤,並拋出out_of_range異常。比如下列代碼:

   string text = "ABCDEF";
    char ch = text.at( 2 );

顯示字符 'C'.

相關主題:
[]
操作符
--------------------------------------------------------------------------------

begin
語法:
iterator begin();


begin()函數返回一個迭代器,指向字符串的第一個元素.

相關主題:
end()
--------------------------------------------------------------------------------

c_str
語法:
const char *c_str();


c_str()函數返回一個指向正規C字符串的指針, 內容與本字符串相同.

相關主題:
[]
操作符
--------------------------------------------------------------------------------

容量(capacity)
語法:
size_type capacity();


capacity()函數返回在重新申請更多的空間前字符串可以容納的字符數. 這個數字至少與 size()一樣大.

相關主題:
max_size(), reserve(), resize(), size(),
--------------------------------------------------------------------------------

比較(compare)
語法:
int compare( const basic_string &str );
int compare( const char *str );
int compare( size_type index, size_type length, const basic_string &str );
int compare( size_type index, size_type length, const basic_string &str,size_type index2,
size_type length2 );
int compare( size_type index, size_type length, const char *str, size_typelength2 );


compare()函數以多種方式比較本字符串和str,返回:

返回值情況
小於零 this < str
this == str
大於零 this > str

不同的函數:

比較自己和str,
比較自己的子串和str,子串以index索引開始,長度爲length
比較自己的子串和str的子串,其中index2length2引用strindexlength引用自己
比較自己的子串和str的子串,其中str的子串以索引0開始,長度爲length2,自己的子串以index開始,長度爲length

相關主題:
操作符
--------------------------------------------------------------------------------

拷貝(copy)
語法:
size_type copy( char *str, size_type num, size_type index );


copy()函數拷貝自己的num個字符到str中(從索引index開始)。返回值是拷貝的字符數


--------------------------------------------------------------------------------

data
語法:
const char *data();


data()函數返回指向自己的第一個字符的指針.

相關主題:
c_str()
--------------------------------------------------------------------------------

empty
語法:
bool empty();


如果字符串爲空則empty()返回真(true),否則返回假(false).


--------------------------------------------------------------------------------

end
語法:
iterator end();


end()函數返回一個迭代器,指向字符串的末尾(最後一個字符的下一個位置).

相關主題:
begin()
--------------------------------------------------------------------------------

刪除(erase)
語法:
iterator erase( iterator pos );
iterator erase( iterator start, iterator end );
basic_string &erase( size_type index = 0, size_type num = npos );


erase()函數可以:

刪除pos指向的字符, 返回指向下一個字符的迭代器,
刪除從startend的所有字符, 返回一個迭代器,指向被刪除的最後一個字符的下一個位置
刪除從index索引開始的num個字符, 返回*this.
參數index num 有默認值, 這意味着erase()可以這樣調用:只帶有index以刪除index後的所有字符,或者不帶有任何參數以刪除所有字符. 例如:

   string s("So, you like donuts, eh? Well, have all the donuts in theworld!");
    cout << "The original string is '" <<s << "'" << endl;

   s.erase( 50, 14 );
    cout << "Now the string is '" << s<< "'" << endl;

   s.erase( 24 );
    cout << "Now the string is '" << s<< "'" << endl;

   s.erase();
    cout << "Now the string is '" << s<< "'" << endl;

將顯示

   The original string is 'So, you like donuts, eh? Well, have all the donuts inthe world!'
    Now the string is 'So, you like donuts, eh? Well, have allthe donuts'
    Now the string is 'So, you like donuts, eh?'
    Now the string is ''


--------------------------------------------------------------------------------

查找(find)
語法:
size_type find( const basic_string &str, size_type index );
size_type find( const char *str, size_type index );
size_type find( const char *str, size_type index, size_type length );
size_type find( char ch, size_type index );


find()函數:

返回str在字符串中第一次出現的位置(從index開始查找)。如果沒找到則返回string::npos,
返回str在字符串中第一次出現的位置(從index開始查找,長度爲length)。如果沒找到就返回string::npos,
返回字符ch在字符串中第一次出現的位置(從index開始查找)。如果沒找到就返回string::npos
例如,

   string str1( "Alpha Beta Gamma Delta" );
    unsigned int loc = str1.find( "Omega", 0 );
    if( loc != string::npos )
      cout << "Found Omega at "<< loc << endl;
    else
      cout << "Didn't find Omega"<< endl;
   
  


--------------------------------------------------------------------------------

find_first_of
語法:
size_type find_first_of( const basic_string &str, size_type index = 0 );
size_type find_first_of( const char *str, size_type index = 0 );
size_type find_first_of( const char *str, size_type index, size_type num );
size_type find_first_of( char ch, size_type index = 0 );


find_first_of()函數:

查找在字符串中第一個與str中的某個字符匹配的字符,返回它的位置。搜索從index開始,如果沒找到就返回string::npos
查找在字符串中第一個與str中的某個字符匹配的字符,返回它的位置。搜索從index開始,最多搜索num個字符。如果沒找到就返回string::npos
查找在字符串中第一個與ch匹配的字符,返回它的位置。搜索從index開始。

相關主題:
find()
--------------------------------------------------------------------------------

find_first_not_of
語法:
size_type find_first_not_of( const basic_string &str, size_type index = 0);
size_type find_first_not_of( const char *str, size_type index = 0 );
size_type find_first_not_of( const char *str, size_type index, size_type num );
size_type find_first_not_of( char ch, size_type index = 0 );


find_first_not_of()函數:

在字符串中查找第一個與str中的字符都不匹配的字符,返回它的位置。搜索從index開始。如果沒找到就返回string::nops
在字符串中查找第一個與str中的字符都不匹配的字符,返回它的位置。搜索從index開始,最多查找num個字符。如果沒找到就返回string::nops
在字符串中查找第一個與ch不匹配的字符,返回它的位置。搜索從index開始。如果沒找到就返回string::nops

相關主題:
find()
--------------------------------------------------------------------------------

find_last_of
語法:
size_type find_last_of( const basic_string &str, size_type index = npos );
size_type find_last_of( const char *str, size_type index = npos );
size_type find_last_of( const char *str, size_type index, size_type num );
size_type find_last_of( char ch, size_type index = npos );


find_last_of()函數:

在字符串中查找最後一個與str中的某個字符匹配的字符,返回它的位置。搜索從index開始。如果沒找到就返回string::nops
在字符串中查找最後一個與str中的某個字符匹配的字符,返回它的位置。搜索從index開始,最多搜索num個字符。如果沒找到就返回string::nops
在字符串中查找最後一個與ch匹配的字符,返回它的位置。搜索從index開始。如果沒找到就返回string::nops

相關主題:
find()
--------------------------------------------------------------------------------

find_last_not_of
語法:
size_type find_last_not_of( const basic_string &str, size_type index = npos);
size_type find_last_not_of( const char *str, size_type index = npos);
size_type find_last_not_of( const char *str, size_type index, size_type num );
size_type find_last_not_of( char ch, size_type index = npos );


find_last_not_of()函數:

在字符串中查找最後一個與str中的字符都不匹配的字符,返回它的位置。搜索從index開始。如果沒找到就返回string::nops
在字符串中查找最後一個與str中的字符都不匹配的字符,返回它的位置。搜索從index開始,最多查找num個字符如果沒找到就返回string::nops
在字符串中查找最後一個與ch不匹配的字符,返回它的位置。搜索從index開始。如果沒找到就返回string::nops

相關主題:
find()
--------------------------------------------------------------------------------

get_allocator
語法:
allocator_type get_allocator();


get_allocator()函數返回本字符串的配置器.


--------------------------------------------------------------------------------

插入(insert)
語法:
iterator insert( iterator i, const char &ch );
basic_string &insert( size_type index, const basic_string &str );
basic_string &insert( size_type index, const char *str );
basic_string &insert( size_type index1, const basic_string &str,size_type index2, size_type num );
basic_string &insert( size_type index, const char *str, size_type num );
basic_string &insert( size_type index, size_type num, char ch );
void insert( iterator i, size_type num, const char &ch );
void insert( iterator i, iterator start, iterator end );


insert()函數的功能非常多:

在迭代器i表示的位置前面插入一個字符ch,
在字符串的位置index插入字符串str,
在字符串的位置index插入字符串str的子串(index2開始,長num個字符),
在字符串的位置index插入字符串strnum個字符,
在字符串的位置index插入num個字符ch的拷貝,
在迭代器i表示的位置前面插入num個字符ch的拷貝,
在迭代器i表示的位置前面插入一段字符,從start開始,以end結束.

相關主題:
replace()
--------------------------------------------------------------------------------

長度(length)
語法:
size_type length();


length()函數返回字符串的長度. 這個數字應該和size()返回的數字相同.

相關主題:
size()
--------------------------------------------------------------------------------

max_size
語法:
size_type max_size();


max_size()函數返回字符串能保存的最大字符數。


--------------------------------------------------------------------------------

rbegin
語法:
const reverse_iterator rbegin();


rbegin()返回一個逆向迭代器,指向字符串的最後一個字符。

相關主題:
rend()
--------------------------------------------------------------------------------

rend
語法:
const reverse_iterator rend();


rend()函數返回一個逆向迭代器,指向字符串的開頭(第一個字符的前一個位置)。

相關主題:
rbegin()
--------------------------------------------------------------------------------

替換(replace)
語法:
basic_string &replace( size_type index, size_type num, const basic_string&str );
basic_string &replace( size_type index1, size_type num1, const basic_string&str, size_type index2,
size_type num2 );
basic_string &replace( size_type index, size_type num, const char *str );
basic_string &replace( size_type index, size_type num1, const char *str,size_type num2 );
basic_string &replace( size_type index, size_type num1, size_type num2,char ch );
basic_string &replace( iterator start, iterator end, const basic_string&str );
basic_string &replace( iterator start, iterator end, const char *str );
basic_string &replace( iterator start, iterator end, const char *str,size_type num );
basic_string &replace( iterator start, iterator end, size_type num, char ch);


replace()函數:

str中的num個字符替換本字符串中的字符,index開始
str中的num2個字符(從index2開始)替換本字符串中的字符,從index1開始,最多num1個字符
str中的num個字符(從index開始)替換本字符串中的字符
str中的num2個字符(從index2開始)替換本字符串中的字符,從index1開始,num1個字符
num2ch字符替換本字符串中的字符,從index開始
str中的字符替換本字符串中的字符,迭代器startend指示範圍
str中的num個字符替換本字符串中的內容,迭代器startend指示範圍,
numch字符替換本字符串中的內容,迭代器startend指示範圍.
例如,以下代碼顯示字符串"They say he carved it himself...find yoursoul-mate, Homer."
    string s = "They say he carved it himself...from aBIGGER spoon";
    string s2 = "find your soul-mate, Homer.";

   s.replace( 32, s2.length(), s2 );

   cout << s << endl;

相關主題:
insert()
--------------------------------------------------------------------------------

保留空間(reserve)
語法:
void reserve( size_type num );


reserve()函數設置本字符串的capacity 以保留num個字符空間。

相關主題:
capacity()
--------------------------------------------------------------------------------

resize
語法:
void resize( size_type num );
void resize( size_type num, char ch );


resize()函數改變本字符串的大小到num, 新空間的內容不確定。也可以指定用ch填充。


--------------------------------------------------------------------------------

rfind
語法:
size_type rfind( const basic_string &str, size_type index );
size_type rfind( const char *str, size_type index );
size_type rfind( const char *str, size_type index, size_type num );
size_type rfind( char ch, size_type index );


rfind()函數:

返回最後一個與str中的某個字符匹配的字符,從index開始查找。如果沒找到就返回string::npos
返回最後一個與str中的某個字符匹配的字符,從index開始查找,最多查找num個字符。如果沒找到就返回string::npos
返回最後一個與ch匹配的字符,從index開始查找。如果沒找到就返回string::npos
例如,在下列代碼中第一次調用rfind()返回string::npos,因爲目標詞語不在開始的8個字符中。然而,第二次調用返回9,因爲目標詞語在開始的20個字符之中。
    int loc;
    string s = "My cat's breath smells like catfood.";

   loc = s.rfind( "breath", 8 );
    cout << "The word breath is at index "<< loc << endl;

   loc = s.rfind( "breath", 20 );
    cout << "The word breath is at index "<< loc << endl;

相關主題:
find()
--------------------------------------------------------------------------------

size
語法:
size_type size();


size()函數返回字符串中現在擁有的字符數。

相關主題:
length(), max_size()
--------------------------------------------------------------------------------

substr
語法:
basic_string substr( size_type index, size_type num = npos );


substr()返回本字符串的一個子串,從index開始,長num個字符。如果沒有指定,將是默認值 string::npos。這樣,substr()函數將簡單的返回從index開始的剩餘的字符串。

例如:

   string s("What we have here is a failure to communicate");

   string sub = s.substr(21);

   cout << "The original string is " << s << endl;
    cout << "The substring is " << sub<< endl;

顯示:

   The original string is What we have here is a failure to communicate
    The substring is a failure to communicate


--------------------------------------------------------------------------------

交換(swap)
語法:
void swap( basic_string &str );


swap()函數把str和本字符串交換。例如:

   string first( "This comes first" );
    string second( "And this is second" );
    first.swap( second );
    cout << first << endl;
    cout << second << endl;

顯示:

    And this is second
    This comes first


詳細解說STL string

0 前言: string 的角色

C++ 語言是個十分優秀的語言,但優秀並不表示完美。還是有許多人不願意使用C或者C++,爲什麼?原因衆多,其中之一就是C/C++的文本處理功能太麻煩,用起來很不方便。以前沒有接觸過其他語言時,每當別人這麼說,我總是不屑一顧,認爲他們根本就沒有領會C++的精華,或者不太懂C++,現在我接觸perl,php, 和Shell腳本以後,開始理解了以前爲什麼有人說C++文本處理不方便了。

舉例來說,如果文本格式是:用戶名 電話號碼,文件名name.txt

Tom 23245332
Jenny 22231231
Heny 22183942
Tom 23245332
...

現在我們需要對用戶名排序,且只輸出不同的姓名。

那麼在shell編程中,可以這樣用:

awk '{print $1}' name.txt | sort | uniq 

簡單吧?

如果使用C/C++就麻煩了,他需要做以下工作:

1.    先打開文件,檢測文件是否打開,如果失敗,則退出。

2.    聲明一個足夠大得二維字符數組或者一個字符指針數組

3.    讀入一行到字符空間

4.    然後分析一行的結構,找到空格,存入字符數組中。

5.    關閉文件

6.    寫一個排序函數,或者使用寫一個比較函數,使用qsort排序

7.    遍歷數組,比較是否有相同的,如果有,則要刪除,copy...

8.    輸出信息

你可以用C++或者C語言去實現這個流程。如果一個人的主要工作就是處理這種類似的文本(例如做apache的日誌統計和分析),你說他會喜歡C/C++麼?

當然,有了STL,這些處理會得到很大的簡化。我們可以使用fstream來代替麻煩的fopenfread fclose, 用vector來代替數組。最重要的是用 string來代替char* 數組,使用sort排序算法來排序,用unique 函數來去重。聽起來好像很不錯 。看看下面代碼(例程1):

#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <fstream>
using namespace std;
int main(){
        ifstream in("name.txt");
        string strtmp;
        vector<string> vect;
        while(getline(in, strtmp, '\n'))
        vect.push_back(strtmp.substr(0, strtmp.find(' ')));
        sort(vect.begin(), vect.end());
        vector<string>::iterator it=unique(vect.begin(), vect.end());
        copy(vect.begin(), it, ostream_iterator<string>(cout, "\n"));
        return 0;
}

也還不錯吧,至少會比想象得要簡單得多!(代碼裏面沒有對錯誤進行處理,只是爲了說明問題,不要效仿).

當然,在這個文本格式中,不用vector而使用map會更有擴充性,例如,還可通過人名找電話號碼等等,但是使用了map就不那麼好用sort了。你可以用map試一試。

這裏string的作用不只是可以存儲字符串,還可以提供字符串的比較,查找等。在sort和unique函數中就默認使用了less和equal_to函數,上面的一段代碼,其實使用了string的以下功能:

1.    存儲功能,在getline() 函數中

2.    查找功能,在find() 函數中

3.    子串功能,在substr() 函數中

4.    string operator < , 默認在sort()函數中調用

5.    string operator == , 默認在unique()函數中調用

總之,有了string後,C++的字符文本處理功能總算得到了一定補充,加上配合STL其他容器使用,其在文本處理上的功能已經與perl,shell, php的距離縮小很多了。 因此掌握string會讓你的工作事半功倍。

1 string 使用

其實,string並不是一個單獨的容器,只是basic_string模板類的一個typedef 而已,相對應的還有wstring,你在string 頭文件中你會發現下面的代碼:

extern "C++" {
        typedef basic_string <char> string;
        typedef basic_string <wchar_t> wstring;
} // extern "C++"

由於只是解釋string的用法,如果沒有特殊的說明,本文並不區分string和 basic_string的區別。

string其實相當於一個保存字符的序列容器,因此除了有字符串的一些常用操作以外,還有包含了所有的序列容器的操作。字符串的常用操作包括:增加、刪除、修改、查找比較、鏈接、輸入、輸出等。詳細函數列表參看附錄。不要害怕這麼多函數,其實有許多是序列容器帶有的,平時不一定用的上。

如果你要想了解所有函數的詳細用法,你需要查看basic_string,或者下載STL編程手冊。這裏通過實例介紹一些常用函數。

1.1 充分使用string 操作符

string 重載了許多操作符,包括 +, +=,<, =, , [], <<, >>等,正式這些操作符,對字符串操作非常方便。先看看下面這個例子:tt.cpp(例程2)

#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;
} 

下面是程序的輸出

-bash-2.05b$ make tt
c++  -O -pipe -march=pentiumpro  tt.cpp  -o tt
-bash-2.05b$ ./tt
Please input your name:Hero
you are not wende!
Hero , Welcome to China!
How are you? Hero , Welcome to China!

有了這些操作符,在STL中仿函數都可以直接使用string作爲參數,例如less, great, equal_to 等,因此在把string作爲參數傳遞的時候,它的使用和int或者float等已經沒有什麼區別了。例如,你可以使用:

map<string, int> mymap;
//以上默認使用了 less<string>

有了operator + 以後,你可以直接連加,例如:

string strinfo="Winter";
string strlast="Hello " + strinfo + "!";
//你還可以這樣:
string strtest="Hello " + strinfo + " Welcome" + " to China" + " !";

看見其中的特點了嗎?只要你的等式裏面有一個string 對象,你就可以一直連續"+",但有一點需要保證的是,在開始的兩項中,必須有一項是string 對象。其原理很簡單:

1.    系統遇到"+"號,發現有一項是string對象。

2.    系統把另一項轉化爲一個臨時 string 對象。

3.    執行 operator + 操作,返回新的臨時string對象。

4.    如果又發現"+"號,繼續第一步操作。

由於這個等式是由左到右開始檢測執行,如果開始兩項都是constchar* ,程序自己並沒有定義兩個constchar* 的加法,編譯的時候肯定就有問題了。

有了操作符以後,assign(),append(), compare(), at()等函數,除非有一些特殊的需求時,一般是用不上。當然at()函數還有一個功能,那就是檢查下標是否合法,如果是使用:

string str="winter";
//下面一行有可能會引起程序中斷錯誤
str[100]='!';
//下面會拋出異常:throws: out_of_range
cout<<str.at(100)<<endl;

瞭解了嗎?如果你希望效率高,還是使用[]來訪問,如果你希望穩定性好,最好使用at()來訪問。

1.2 眼花繚亂的string 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的比較一定要用string::size_type來使用,不要直接使用int或者unsigned int等類型。其實string::npos表示的是-1,看看頭文件:

template <class _CharT, class _Traits, class _Alloc> 
const basic_string<_CharT,_Traits,_Alloc>::size_type 
basic_string<_CharT,_Traits,_Alloc>::npos 
= basic_string<_CharT,_Traits,_Alloc>::size_type) -1;

find和rfind 都還比較容易理解,一個是正向匹配,一個是逆向匹配,後面的參數pos都是用來指定起始查找位置。對於find_first_of和find_last_of就不是那麼好理解。

find_first_of是給定一個要查找的字符集,找到這個字符集中任何一個字符所在字符串中第一個位置。或許看一個例子更容易明白。

有這樣一個需求:過濾一行開頭和結尾的所有非英文字符。看看用string如何實現:

#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;
        return 0;
}

這裏把所有的英文字母大小寫作爲了需要查找的字符集,先查找第一個英文字母的位置,然後查找最後一個英文字母的位置,然後用substr來的到中間的一部分,用於輸出結果。下面就是其結果:

Hello Word

前面的符號和後面的符號都沒有了。像這種用法可以用來查找分隔符,從而把一個連續的字符串分割成爲幾部分,達到shell 命令中的 awk 的用法。特別是當分隔符有多個的時候,可以一次指定。例如有這樣的需求:

張三|3456123, 湖南
李四,4564234| 湖北
王小二, 4433253|北京
...

我們需要以"|" ","爲分隔符,同時又要過濾空格,把每行分成相應的字段。可以作爲你的一個家庭作業來試試,要求代碼簡潔。

1.3 string insert,replace, erase

瞭解了string的操作符,查找函數和substr,其實就已經瞭解了string的80%的操作了。insert函數,replace函數和erase函數在使用起來相對簡單。下面以一個例子來說明其應用。

string只是提供了按照位置和區間的replace函數,而不能用一個string字串來替換指定string中的另一個字串。這裏寫一個函數來實現這個功能:

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.replace(pos, srclen, strdst);
                pos += dstlen;
        }
}

看看如何調用:

#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;
}

其輸出結果:

Orign string is :
This is Winter, Winter is a programmer. Do you know Winter?
After replace Winter with wende, the string is :
This is wende, wende is a programmer. Do you know wende?

如果不用replace函數,則可以使用erase和insert來替換,也能實現string_replace函數的功能:

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

當然,這種方法沒有使用replace來得直接。

2 string 和 C風格字符串

現在看了這麼多例子,發現constchar* 可以和string 直接轉換,例如我們在上面的例子中,使用

string_replace(strinfo, "Winter", "wende");

來代用

void string_replace(string & strBig, const string & strsrc, const string &strdst) 

在C語言中只有char*和 const char*,爲了使用起來方便,string提供了三個函數滿足其要求:

const charT* c_str() const 
const charT* data() const 
size_type copy(charT* buf, size_type n, size_type pos = 0) const 

其中:

1.    c_str 直接返回一個以\0結尾的字符串。

2.    data 直接以數組方式返回string的內容,其大小爲size()的返回值,結尾並沒有\0字符。

3.    copy 把string的內容拷貝到buf空間中。

你或許會問,c_str()的功能包含data(),那還需要data()函數幹什麼?看看源碼:

const charT* c_str () const
{ if (length () == 0) return ""; terminate (); return data (); }

原來c_str()的流程是:先調用terminate(),然後在返回data()。因此如果你對效率要求比較高,而且你的處理又不一定需要以\0的方式結束,你最好選擇data()。但是對於一般的C函數中,需要以constchar*爲輸入參數,你就要使用c_str()函數。

對於c_str()data()函數,返回的數組都是由string本身擁有,千萬不可修改其內容。其原因是許多string實現的時候採用了引用機制,也就是說,有可能幾個string使用同一個字符存儲空間。而且你不能使用sizeof(string)來查看其大小。詳細的解釋和實現查看EffectiveSTL的條款15:小心string實現的多樣性

另外在你的程序中,只在需要時才使用c_str()或者data()得到字符串,每調用一次,下次再使用就會失效,如:

string strinfo("this is Winter");
...
//最好的方式是:
foo(strinfo.c_str());
//也可以這麼用:
const char* pstr=strinfo.c_str();
foo(pstr);
//不要再使用了pstr了, 下面的操作已經使pstr無效了。
strinfo += " Hello!";
foo(pstr);//錯誤!

會遇到什麼錯誤?當你幸運的時候pstr可能只是指向"thisis Winter Hello!"的字符串,如果不幸運,就會導致程序出現其他問題,總會有一些不可遇見的錯誤。總之不會是你預期的那個結果。

3 string 和 CharactorTraits

瞭解了string的用法,該詳細看看string的真相了。前面提到string只是basic_string的一個typedef。看看basic_string的參數:

template <class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string
{
        //...
}

char_traits不僅是在basic_string 中有用,在basic_istream和 basic_ostream中也需要用到。

就像SteveDonovan在過度使用C++模板中提到的,這些確實有些過頭了,要不是系統自己定義了相關的一些屬性,而且用了個typedef,否則還真不知道如何使用。

但複雜總有複雜道理。有了char_traits,你可以定義自己的字符串類型。當然,有了char_traits< char > 和char_traits< wchar_t > 你的需求使用已經足夠了,爲了更好的理解string,咱們來看看char_traits都有哪些要求。

如果你希望使用你自己定義的字符,你必須定義包含下列成員的結構:

表達式

描述

char_type

字符類型

int_type

int 類型

pos_type

位置類型

off_type

表示位置之間距離的類型

state_type

表示狀態的類型

assign(c1,c2)

把字符c2賦值給c1

eq(c1,c2)

判斷c1,c2 是否相等

lt(c1,c2)

判斷c1是否小於c2

length(str)

判斷str的長度

compare(s1,s2,n)

比較s1和s2的前n個字符

copy(s1,s2, n)

把s2的前n個字符拷貝到s1中

move(s1,s2, n)

把s2中的前n個字符移動到s1中

assign(s,n,c)

把s中的前n個字符賦值爲c

find(s,n,c)

在s的前n個字符內查找c

eof()

返回end-of-file

to_int_type(c)

將c轉換成int_type

to_char_type(i)

將i轉換成char_type

not_eof(i)

判斷i是否爲EOF

eq_int_type(i1,i2)

判斷i1和i2是否相等

想看看實際的例子,你可以看看sgiSTL的char_traits結構源碼.

現在默認的string版本中,並不支持忽略大小寫的比較函數和查找函數,如果你想練練手,你可以試試改寫一個char_traits, 然後生成一個case_string類,也可以在string上做繼承,然後派生一個新的類,例如:ext_string,提供一些常用的功能,例如:

1.    定義分隔符。給定分隔符,把string分爲幾個字段。

2.    提供替換功能。例如,用winter, 替換字符串中的wende

3.    大小寫處理。例如,忽略大小寫比較,轉換等

4.    整形轉換。例如把"123"字符串轉換爲123數字。

這些都是常用的功能,如果你有興趣可以試試。其實有人已經實現了,看看Extended STL string。如果你想偷懶,下載一個頭文件就可以用,有了它確實方便了很多。要是有人能提供一個支持正則表達式的string,我會非常樂意用。

4 string 建議

使用string的方便性就不用再說了,這裏要重點強調的是string的安全性。

1.    string並不是萬能的,如果你在一個大工程中需要頻繁處理字符串,而且有可能是多線程,那麼你一定要慎重(當然,在多線程下你使用任何STL容器都要慎重)。

2.    string的實現和效率並不一定是你想象的那樣,如果你對大量的字符串操作,而且特別關心其效率,那麼你有兩個選擇,首先,你可以看看你使用的STL版本中string實現的源碼;另一選擇是你自己寫一個只提供你需要的功能的類。

3.    string的c_str()函數是用來得到C語言風格的字符串,其返回的指針不能修改其空間。而且在下一次使用時重新調用獲得新的指針。

4.    string的data()函數返回的字符串指針不會以'\0'結束,千萬不可忽視。

5.    儘量去使用操作符,這樣可以讓程序更加易懂(特別是那些腳本程序員也可以看懂)

5 小結

難怪有人說:
string 使用方便功能強,我們一直用它!

6 附錄

string 函數列表

函數名

描述

begin

得到指向字符串開頭的Iterator

end

得到指向字符串結尾的Iterator

rbegin

得到指向反向字符串開頭的Iterator

rend

得到指向反向字符串結尾的Iterator

size

得到字符串的大小

length

和size函數功能相同

max_size

字符串可能的最大大小

capacity

在不重新分配內存的情況下,字符串可能的大小

empty

判斷是否爲空

operator[]

取第幾個元素,相當於數組

c_str

取得C風格的const char* 字符串

data

取得字符串內容地址

operator=

賦值操作符

reserve

預留空間

swap

交換函數

insert

插入字符

append

追加字符

push_back

追加字符

operator+=

+= 操作符

erase

刪除字符串

clear

清空字符容器中所有內容

resize

重新分配空間

assign

和賦值操作符一樣

replace

替代

copy

字符串到空間

find

查找

rfind

反向查找

find_first_of

查找包含子串中的任何字符,返回第一個位置

find_first_not_of

查找不包含子串中的任何字符,返回第一個位置

find_last_of

查找包含子串中的任何字符,返回最後一個位置

find_last_not_of

查找不包含子串中的任何字符,返回最後一個位置

substr

得到字串

compare

比較字符串

operator+

字符串鏈接

operator==

判斷是否相等

operator!=

判斷是否不等於

operator<

判斷是否小於

operator>>

從輸入流中讀入字符串

operator<<

字符串寫入輸出流

getline

從輸入流中讀入一行

 


之所以拋棄char*的字符串而選用C++標準程序庫中的string類,是因爲他和前者比較起來,不必 
擔心內存是否足夠、字符串長度等等,而且作爲一個類出現,他集成的操作函數足以完成我們大多數情況下(甚至是100%)的需要。我們可以用 = 進行賦值操作,== 
進行比較,+ 做串聯(是不是很簡單?)。我們儘可以把它看成是C++的基本數據類型。 

首先,爲了在我們的程序中使用string類型,我們必須包含頭文件 <string>。如下: 
#include <string> //注意這裏不是string.h string.h是C字符串頭文件 

1.聲明一個C++字符串 
聲明一個字符串變量很簡單: 
string Str; 
這樣我們就聲明瞭一個字符串變量,但既然是一個類,就有構造函數和析構函數。上面的聲明沒有傳入參數,所以就直接使用了string的默認的構造函數,這個函數所作的就是把Str初始化爲一個空字符串。String類的構造函數和析構函數如下: 

a) string s; //生成一個空字符串s 
b) string s(str) //拷貝構造函數 生成str的複製品 
c) string s(str,stridx) //將字符串str內"始於位置stridx"的部分當作字符串的初值 
d) string s(str,stridx,strlen) //將字符串str內"始於stridx且長度頂多strlen"的部分作爲字符串的初值 
e) string s(cstr) //將C字符串作爲s的初值 
f) string s(chars,chars_len) //將C字符串前chars_len個字符作爲字符串s的初值。 
g) string s(num,c) //生成一個字符串,包含num個c字符 
h) string s(beg,end) //以區間beg;end(不包含end)內的字符作爲字符串s的初值 
i) s.~string() //銷燬所有字符,釋放內存 
都很簡單,我就不解釋了。 

2.字符串操作函數 
這裏是C++字符串的重點,我先把各種操作函數羅列出來,不喜歡把所有函數都看完的人可以在這裏找自己喜歡的函數,再到後面看他的詳細解釋。 
a) =,assign() //賦以新值 
b) swap() //交換兩個字符串的內容 
c) +=,append(),push_back() //在尾部添加字符 
d) insert() //插入字符 
e) erase() //刪除字符 
f) clear() //刪除全部字符 
g) replace() //替換字符 
h) + //串聯字符串 
i) ==,!=,<,<=,>,>=,compare() //比較字符串 
j) size(),length() //返回字符數量 
k) max_size() //返回字符的可能最大個數 
l) empty() //判斷字符串是否爲空 
m) capacity() //返回重新分配之前的字符容量 
n) reserve() //保留一定量內存以容納一定數量的字符 
o) [ ], at() //存取單一字符 
p) >>,getline() //從stream讀取某值 
q) << //將謀值寫入stream 
r) copy() //將某值賦值爲一個C_string 
s) c_str() //將內容以C_string返回 
t) data() //將內容以字符數組形式返回 
u) substr() //返回某個子字符串 
v)查找函數 
w)begin() end() //提供類似STL的迭代器支持 
x) rbegin() rend() //逆向迭代器 
y) get_allocator() //返回配置器 
下面詳細介紹: 

2.1 C++字符串和C字符串的轉換 

++提供的由C++字符串得到對應的C_string的方法是使用data()、c_str()和copy(),其中,data()以字符數組的形式返回字符串內容,但並不添加’\0’。c_str()返回一個以‘\0’結尾的字符數組,而copy()則把字符串的內容複製或寫入既有的c_string或 
字符數組內。C++字符串並不以’\0’結尾。我的建議是在程序中能使用C++字符串就使用,除非萬不得已不選用c_string。由於只是簡單介紹,詳細介紹掠過,誰想進一步瞭解使用中的注意事項可以給我留言(到我的收件箱)。我詳細解釋。 


2.2 大小和容量函數 
一個C++字符 串存在三種大小:a)現有的字符數,函數是size()和length(),他們等效。Empty()用來檢查字符串是否爲空。b)max_size() 
這個大小是指當前C++字符串最多能包含的字符數,很可能和機器本身的限制或者字符串所在位置連續內存的大小有關係。我們一般情況下不用關心他,應該大小足夠我們用的。但是不夠用的話,會拋出length_error異常c)capacity()重新分配內存之前 
string所能包含的最大字符數。這裏另一個需要指出的是reserve()函數,這個函數爲string重新分配內存。重新分配的大小由其參數決定, 
默認參數爲0,這時候會對string進行非強制性縮減。 

還有必要再重複一下C++字符串和C字符串轉換的問 
題,許多人會遇到這樣的問題,自己做的程序要調用別人的函數、類什麼的(比如數據庫連接函數Connect(char*,char*)),但別人的函數參 
數用的是char*形式的,而我們知道,c_str()、data()返回的字符數組由該字符串擁有,所以是一種const 
char*,要想作爲上面提及的函數的參數,還必須拷貝到一個char*,而我們的原則是能不使用C字符串就不使用。那麼,這時候我們的處理方式是:如果 
此函數對參數(也就是char*)的內容不修改的話,我們可以這樣Connect((char*)UserID.c_str(), 
(char*)PassWD.c_str()),但是這時候是存在危險的,因爲這樣轉換後的字符串其實是可以修改的(有興趣地可以自己試一試),所以我強調除非函數調用的時候不對參數進行修改,否則必須拷貝到一個char*上去。當然,更穩妥的辦法是無論什麼情況都拷貝到一個char*上去。同時我們也祈 
禱現在仍然使用C字符串進行編程的高手們(說他們是高手一點兒也不爲過,也許在我們還穿開襠褲的時候他們就開始編程了,哈哈…)寫的函數都比較規範,那樣 
我們就不必進行強制轉換了。 
2.3元素存取 

我們可以使用下標操作符[]和函數at()對元素包含的字符進行訪問。但是應該注意的是操作符[]並不檢查索引是否有效(有效索引0~str.length()),如果索引失效,會引起未定義的行爲。而at()會檢查,如果使用 
at()的時候索引無效,會拋出out_of_range異常。 
有一個例外不得不說,const string 
a;的操作符[]對索引值是a.length()仍然有效,其返回值是’\0’。其他的各種情況,a.length()索引都是無效的。舉例如下: 
const string Cstr("const string"); 
string Str("string"); 

Str[3]; //ok 
Str.at(3); //ok 

Str[100]; //未定義的行爲 
Str.at(100); //throw out_of_range 

Str[Str.length()] //未定義行爲 
Cstr[Cstr.length()] //返回 ‘\0’ 
Str.at(Str.length());//throw out_of_range 
Cstr.at(Cstr.length()) ////throw out_of_range 

我不贊成類似於下面的引用或指針賦值: 
char& r=s[2]; 
char* p= &s[3]; 
因爲一旦發生重新分配,r,p立即失效。避免的方法就是不使用。 

2.4比較函數 
C ++字符串支持常見的比較操作符(>,>=,<,<=,==,!=),甚至支持string與C-string的比較(如 
str<"hello")。在使用>,>=,<,<=這些操作符的時候是根據"當前字符特性"將字符按字典順序進行逐一得 
比較。字典排序靠前的字符小,比較的順序是從前向後比較,遇到不相等的字符就按這個位置上的兩個字符的比較結果確定兩個字符串的大小。同時,string 
("aaaa") <string(aaaaa)。 
另一個功能強大的比較函數是成員函數compare()。他支持多參數處理,支持用索引值和長度定位子串來進行比較。他返回一個整數來表示比較結果,返回值意義如下:0-相等 
〉0-大於 <0-小於。舉例如下: 
string s("abcd"); 

s.compare("abcd"); //返回0 
s.compare("dcba"); //返回一個小於0的值 
s.compare("ab"); //返回大於0的值 

s.compare(s); //相等 
s.compare(0,2,s,2,2); //用"ab"和"cd"進行比較 小於零 
s.compare(1,2,"bcx",2); //用"bc"和"bc"比較。 
怎麼樣?功能夠全的吧!什麼?還不能滿足你的胃口?好吧,那等着,後面有更個性化的比較算法。先給個提示,使用的是STL的比較算法。什麼?對STL一竅不通?靠,你重修吧! 


2.5 更改內容 
這在字符串的操作中佔了很大一部分。 

首先講賦值,第一個賦值方法當然是使用操作符=,新值可以是string(如:s=ns) 
、c_string(如:s="gaint")甚至單一字符(如:s=’j’)。還可以使用成員函數assign(),這個成員函數可以使你更靈活的對字符串賦值。還是舉例說明吧: 

s.assign(str); //不說 
s.assign(str,1,3);//如果str是"iamangel" 就是把"ama"賦給字符串 
s.assign(str,2,string::npos);//把字符串str從索引值2開始到結尾賦給s 
s.assign("gaint"); //不說 
s.assign("nico",5);//把’n’ ‘I’ ‘c’ ‘o’ ‘\0’賦給字符串 
s.assign(5,’x’);//把五個x賦給字符串 
把字符串清空的方法有三個:s="";s.clear();s.erase();(我越來越覺得舉例比說話讓別人容易懂!)。 
string提供了很多函數用於插入(insert)、刪除(erase)、替換(replace)、增加字符。 
先說增加字符(這裏說的增加是在尾巴上),函數有 +=、append()、push_back()。舉例如下: 
s+=str;//加個字符串 
s+="my name is jiayp";//加個C字符串 
s+=’a’;//加個字符 

s.append(str); 
s.append(str,1,3);//不解釋了 同前面的函數參數assign的解釋 
s.append(str,2,string::npos)//不解釋了 

s.append("my name is jiayp"); 
s.append("nico",5); 
s.append(5,’x’); 

s.push_back(‘a’);//這個函數只能增加單個字符 對STL熟悉的理解起來很簡單 

也許你需要在string中間的某個位置插入字符串,這時候你可以用insert()函數,這個函數需要你指定一個安插位置的索引,被插入的字符串將放在這個索引的後面。 

s.insert(0,"my name"); 
s.insert(1,str); 
這 種形式的insert()函數不支持傳入單個字符,這時的單個字符必須寫成字符串形式(讓人噁心)。既然你覺得噁心,那就不得不繼續讀下面一段話:爲了插 
入單個字符,insert()函數提供了兩個對插入單個字符操作的重載函數:insert(size_type index,size_type num,chart 
c)和insert(iterator pos,size_type num,chart 
c)。其中size_type是無符號整數,iterator是char*,所以,你這麼調用insert函數是不行的:insert(0,1, 
’j’);這時候第一個參數將轉換成哪一個呢?所以你必須這麼寫:insert((string::size_type)0,1,’j’)!第二種形式指 
出了使用迭代器安插字符的形式,在後面會提及。順便提一下,string有很多操作是使用STL的迭代器的,他也儘量做得和STL靠近。 
刪除函數erase()的形式也有好幾種(真煩!),替換函數replace()也有好幾個。舉例吧: 
string s="il8n"; 
s.replace(1,2,"nternationalizatio");//從索引1開始的2個替換成後面的C_string 
s.erase(13);//從索引13開始往後全刪除 
s.erase(7,5);//從索引7開始往後刪5個 

2.6提取子串和字符串連接 
題取子串的函數是:substr(),形式如下: 
s.substr();//返回s的全部內容 
s.substr(11);//從索引11往後的子串 
s.substr(5,6);//從索引5開始6個字符 
把兩個字符串結合起來的函數是+。(誰不明白請致電120) 

2.7輸入輸出操作 
1.>> 從輸入流讀取一個string。 
2.<< 把一個string寫入輸出流。 
另一個函數就是getline(),他從輸入流讀取一行內容,直到遇到分行符或到了文件尾。 

2.8搜索與查找 
查找函數很多,功能也很強大,包括了: 
find() 
rfind() 
find_first_of() 
find_last_of() 
find_first_not_of() 
find_last_not_of() 
這些函數返回符合搜索條件的字符區間內的第一個字符的索引,沒找到目標就返回npos。所有的函數的參數說明如下: 
第一個參數是被搜尋的對象。第二個參數(可有可無)指出string內的搜尋起點索引,第三個參數(可有可無)指出搜尋的字符個數。比較簡單,不多說不理解的可以向我提出,我再仔細的解答。當然,更加強大的STL搜尋在後面會有提及。 

最 
後再說說npos的含義,string::npos的類型是string::size_type,所以,一旦需要把一個索引與npos相比,這個索引值必須是string::size)type類型的,更多的情況下,我們可以直接把函數和npos進行比較(如:if(s.find("jia")== 
string::npos))。 

 

發佈了100 篇原創文章 · 獲贊 8 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章