1. 程式人生 > >C++之字串

C++之字串

C++字串

C中的字串

C語言中不提供字串型別,因此所謂的字串不過是一組以’\0’結尾的字元序列。
C語言中通常以char型的陣列來儲存字串,如下例:

#include <stdio.h>
#include <string.h>
int main()
{
	char s[] = "Hello World!";
	printf("%s\nLength of s : %d\n  Size of s : %d"
, s, strlen(s),sizeof(s)); return 0; }
Hello World!
Length of s : 12
  Size of s : 13

上例中,strlen()函式用於求字元陣列長度,而sizeof關鍵字用於求字元陣列佔用的位元組數。可以看出,字串佔用的位元組數比陣列長度大1,這也印證了上面說到的C語言中的字串實際上是以’\0’結尾的字元陣列。

C語言提供了<string.h>來方便程式設計師處理字串,<string.h>中主要包含以下用於字串處理的函式:

函式 函式 函式
strcpy() stricmp () strtec()
strncpy() strerror() strspn()
strcat() strcmpi() strstr()
strchr() strncmp() strtod()
strcmp() strncpy() strtok()
strnicmp() strtol() strlen()
strnset() strupr() strcspn()
strpbrk() swab() strdup()
strrchr()

上述函式的具體用法不在此進行描述。

當然,C++仍舊保留了這種C語言的字串操作方式,而<string.h>中的相關內容以C++的表現形式被包含於<cstring>中。為了方便描述,本文後面的內容把C語言下的字串用cstring來表示。

C++中的字串

C++中除了支援C中的字元陣列外,還提供了一個更加強大的string類。但由於string類涉及太多面向物件的內容,這裡只作一些簡單的討論。

字串建立

C++對string的建構函式實現了多個過載,因此有很多不同的方法來定義並初始化一個字串。下面是幾個常用的方式:

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s1;//建立空串
	string s2("Hello World!");          //以cstring作為初值
	string s3(s2);                      //以string作為初值,相當於拷貝
	string s4(s2, 5);                   //取string第5個字元之後的所有字元
	string s5("Hello World!", 5);       //取cstring的前5個字元
	string s6(s2, 6, 5);                //取string第6個字元之後的5個字元
	string s7("Hello World", 6, 5);     //取cstring第6個字元之後的5個字元
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s4 = " << s4 << endl;
	cout << "s5 = " << s5 << endl;
	cout << "s6 = " << s6 << endl;
	cout << "s7 = " << s7 << endl;
	return 0;
}
s1 =
s2 = Hello World!
s3 = Hello World!
s4 =  World!
s5 = Hello
s6 = World
s7 = World

這裡需要注意的是s4和s5的不同,當分別以string和cstring作為源建立string時,兩種過載的第二個引數意義是不同的,前者為起始位置,後者為字元數。

字元元素存取

C++提供了三種方式對string中的字元進行索引,分別為:
1. 下標索引 [ i ]
2. at( i )訪問
3. back()/front()訪問首字元和末字元。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s("Hello World!");//以cstring作為初值
	cout << s[0] << endl;
	cout << s.at(0) << endl;
	cout << s.front() << endl;
	cout << s.back() << endl;
	return 0;
}
H
H
H
!

字串賦值

string類過載了“=”操作符,因此可以直接用"="進行賦值,此外,C++還提供了更加靈活的assign()成員函式來對字串進行賦值。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s1, s2, s3, s4, s5, s6;
	s1 = "Hello World !";//=cstring
	s2 = s1;			 //=string
	s3.assign(s1);		 //assign(string)
	s3.assign("Hello World !");//assign(cstring)
	s4.assign("Hello World !", 5);//assign(cstring, n)	
	s5.assign(s1, 5);		//assign(string, pos)
	s6.assign(12, '-');		//assign(n, char)
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
	cout << s6 << endl;
	return 0;
}
Hello World !
Hello World !
Hello World !
Hello
 World !
------------

同使用建構函式建立字串時相同,這裡的s4和s5也得到了不同的結果,因此對於ctring和string,assign實現了不同的過載,意義同構造函式。

字串操作

C++提供了許多對字串進行操作的方法,包括增、刪、查詢、替換、交換、屬性獲取等許多方便的功能。下面就幾個常用的方法進行簡要的總結。

1.增刪操作

string過載了”+=操作符",因此可以利用“+=”來增長字串。此外,C++還提供了append()和push_back()來對字串進行增操作,erase()來對字串進行減操作,clear()來對字串進行清空等操作。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World !";
	cout << "s = " << s << endl;
	s += " I'm";//後面增加字串" I'm"
	s.append(" C++");//後面增加字串" C++"
	s.push_back('!');//後面增加'!'字元
	cout << "s = " << s << endl;
	s.erase(5);//刪除第5個字元後的所有字元
	cout << "s = " << s << endl;
	s.erase(1,3);//刪除第1到3個字元
	cout << "s = " << s << endl;
	s.clear();//清空字串
	cout << "s = " << s << endl;
	return 0;
}
s = Hello World !
s = Hello World ! I'm C++!
s = Hello
s = Ho
s =

2.查詢操作

string類提供了一些用於字元查詢和字串查詢的方法,主要有:
find()
rfind()
find_first_of()
find_last_of()
find_first_not_of()
find_last_not_of()

string類對上述6個方法進行了多個過載,可以滿足大多數情況下的要求。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World ! Hello World !";
	int pos0 = s.find('l');//查詢字元‘l’的位置
	cout << pos0 << endl;
	int pos1 = s.find('l', 10);//從下標10開始查詢字元‘l'的位置
	cout << pos1 << endl;
	int pos2 = s.find("World");//查詢字串"World"的位置
	cout << pos2 << endl;
	int pos3 = s.find("World", 10);//從下標10開始查詢字串"World"的位置
	cout << pos3 << endl;
	int pos4 = s.find("World????", 10, 5);//從下標10開始查詢字串"Wordl????"的前五個字元"World"的位置
	cout << pos4 << endl;
	return 0;
}
2
16
6
20
20

這裡僅給出了find的用法,其餘五個方法的用法類似。
此外,STL中還提供了許多功能強大的查詢功能,同樣可以對字串進行操作,這裡不展開討論。

3.子串操作

string類提供了提取字串的方法substr(),用法如下:

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World !";
	string s1 = s.substr();    //全部
	string s2 = s.substr(6);   //從下標6開始的所有字元
	string s3 = s.substr(2, 7);//從下標2開始7個字元,不是2到7!
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	return 0;
}
Hello World !
World !
llo Wor

4.屬性操作

string類提供了一些關於屬性操作的方法,較常用的如下:
size() 返回字串大小
length() 返回字串長度,和size()幾乎沒區別
max_size() 可能的最大大小
empty() 判斷字串是否為空

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World !";
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.max_size() << endl;
	cout << s.empty() << endl;
	return 0;
}

13
13
2147483647
0

字串流

sstream庫中定義了三個類:istringstream、ostringstream和stringstream,分別用來進行字串流的輸入、輸出和輸入輸出操作。

字串流常用於資料轉換字串的處理,下面分別簡單的介紹一下兩個功能的實現:

1.資料轉換

在C語言中,將float型資料與字元陣列之間的相互轉換可以這樣做:

#include <stdio.h>
int main() {
	char s[12];
	float ft0 = 32.23,ft1;
	sprintf(s, "%f", ft0);//float轉字元陣列
	sscanf(s, "%f", &ft1);//字元陣列轉float
	for (int i = 0; s[i] != '\0'; ++i) printf("%c ", s[i]);
	printf("\n%f\n", ft1);
	return 0;
}

當然,在C++中也可以這樣做,但C++中提供的字串流可以提供更強大的功能。下面是一個例子:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
	float data, sum=0;
	string line = "12.34 23.45 34.56 45.67";
    stringstream ss(line);//以string建立字串流
	//stringstream ss; ss << line;
	while (ss >> data) sum += data;//逐個輸出求和
	cout << "sum = " << sum << endl;
	return 1;
}

上例中以字串"12.34 23.45 34.56 45.67"建立一個字串流ss,然後依次從字串流ss中讀取資料進行求和,最後輸出求和的結果。

下面再舉一個數據轉換的簡單例子:

void float_to_string(string &s, float ft) {
	stringstream ss;
	ss << ft;
	s=ss.str();
	//ss >> s;
}

這個例子通過字串流將float型資料轉換為string,因為不用擔心string的長度問題,所以也就不用擔心是否會溢位。將其他型別轉換為string的做法也是一樣的,通過泛型程式設計可以實現任意資料型別之間的轉換。

2.輸入和輸出

字串流還可以用於輸入與輸出。上面提到,istringstream、ostringstream和stringstream,分別用來進行字串流的輸入、輸出和輸入輸出操作。我們利用stringstream可以很方便的對從標準輸入讀取的資料進行處理。將上面求和的例子稍作修改如下:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
	float data, sum = 0;
	string line;
	stringstream ss;
	while (getline(cin, line)) {
		ss << line; sum = 0;//流入
		while (ss >> data) sum += data;//流出求和
		cout << "sum = " << sum << endl;//列印
		ss.clear();//清空
	}
	return 1;
}

上例中,使用string類提供的getline可以從某個輸入流(cin)中讀取一行資料賦值給字串。利用字串流來臨時儲存資料並且進行資料轉換,然後逐個讀出求和。

總結

(1) C++仍然保留了C語言中字元陣列的機制。
(2) C++還提供更加靈活且強大的string類。
(3) string類提供了非常靈活的建立、操作方法。
(4) 字串流可以很方便的用於資料轉換和資料處理。