C++中 字符串的常見操作


字符串分割

在一些比較流行的語言中,字符串分割是一個比較重要的方法,不論是在python,java這樣的系統級語言還是js這樣的前端腳本都會在用到字符串的分割,然而在c++中卻沒有這樣的方法用來調用。但是在boost中卻提供分割方法。

使用vector實現

下面是用vector實現的一個簡單的split函數,借助string::find函數查找匹配子串的位置,然后截取剩下的字符串之后繼續處理,實現對原字符串的完整處理。

vector<string> split(string &s, string &delim, bool removeEmpty = false, bool fullMatch = false) {

    vector<string> result;

    string::size_type start = 0, skip = 1;

 

    // 使用整個字符串進行查找,之后會直接跳過整個子字符串

    if (fullMatch) {

        skip = delim.length();

    }

 

    while (start != string::npos) {

        // 從start位置開始查找子字符串delim第一次出現的位置

        string::size_type finsh = s.find(delim, start);

 

        if (skip == 0) {

            finsh = string::npos;

        }

 

        // 從start開始到(finsh - start)處獲得子字符串

        // 獲得匹配字符串之前的字符串

        string token = s.substr(start, finsh - start);

 

        // 對token進行判斷並決定是否移除空

        if (!(removeEmpty && token.empty())) {

            // 將匹配字符串之前的字符串放進向量中

            result.push_back(token);

        }

 

        // 判斷此時是否到了原字符串的末尾

        if ((start = finsh) != string::npos) {

            // 將子字符串放進向量中,是為了保證原字符串的字符不丟失

            result.push_back(delim);

            // 將查找位置向前移動skip個位置

            start = start + skip;

        }

    }

 

    return result;

}

關於字符串的輸入方法: std::cin , 多個單詞使用函數std::getline(std::cin, s)

這個函數接受兩個參數:一個輸入流對象和一個 string 對象。getline 函數從輸入流的下一行讀取,並保存讀取的內容到不包括換行符。和輸入操作符不一樣的是,getline 並不忽略行開頭的換行符。只要 getline 遇到換行符,即便它是輸入的第一個字符,getline 也將停止讀入並返回。如果第一個字符就是換行符,則 string 參數將被置為空 string。

 

由於getline函數返回時丟棄換行符,換行符將不會存儲在string對象中。

String的操作方法

s.empty()

Returns true if s is empty; otherwise returns false

如果 s 為空串,則返回 true,否則返回 false。

s.size()

Returns number of characters in s

返回 s 中字符的個數

s[n]

Returns the character at position n in s; positions start at 0.

返回 s 中位置為 n 的字符, 位置從 0 開始計數

【注意:1、引用下標時如果超出下標作用范圍就會引起溢出錯誤。同樣不會報錯!2、索引的實際數據類型是類型 unsigned 類型string::size_type。】

 

 

#include <iostream>

#include <string>

 

int main()

{

std::string s = "hello world";

std::cout<<s<<std::endl;

for (std::string::size_type ix = 0; ix != s.size(); ++ix)

s[ix] = '*';

    std::cout<<"Now s is:"<<s<<std::endl;

    std::cout<<"s's len is:"<<s.size()<<", s[12]="<<s[100]<<std::endl;

    return 0;

}

注意:循環中使用了 std::string::size_type ix = 0;請使用string內置類型size_type來操作。 因為int型可能不夠string的長度,所以內置類型size_type(實際可以認為是 unsigned)被創建,保證各機器的兼容性, 避免溢出(和下標溢出可不是一回事)。 任何存儲 string 的 size 操作結果的變量必須為 string::size_type 類型。特別重要的是,還要把 size 的返回值賦給一個 int 變量。

 

s1 + s2

Returns a string equal to the concatenation of s1 and s2

把 s1 和s2 連接成一個新字符串,返回新生成的字符串

【備注: 可以連續加,和Python類似。string s3 = s1 + ", " + s2 + "\n";。注意:當進行 string 對象和字符串字面值混合連接操作時,+ 操作符的左右操作數必須至少有一個是 string 類型的【想象下級聯也就知道這確實是有道理的】。----1、也就是說+連接必須保證前兩個有一個為string類型!2、字符串字面值不能直接相加,字符串字面值和string是不同類型的,字符串里面沒有空字符'\0'。】

 

s1 = s2

Replaces characters in s1 by a copy of s2

把 s1 內容替換為 s2 的副本

【備注:。它必須先把 s1 占用的相關內存釋放掉,然后再分配給 s2 足夠存放 s2 副本的內存空間,最后把 s2 中的所有字符復制到新分配的內存空間。】

v1 == v2

Returns true if v1 and v2 are equal; false otherwise

比較 v1 與 v2 的內容,相等則返回 true,否則返回 false

!=, <, <=, >, and >=

Have their normal meanings

保持這些操作符慣有的含義

cctype Functions

我們經常要對 string 對象中的單個字符進行處理,例如,通常需要知道某個特殊字符是否為空白字符、字母或數字。以下 列出了各種字符操作函數,適用於 string 對象的字符(或其他任何 char 值)。這些函數都在cctype 頭文件中定義。

 

isalnum(c)

True if c is a letter or a digit.如果 c 是字母或數字,則為 True。

isalpha(c)

true if c is a letter.如果 c 是字母,則為 true。

iscntrl(c)

true if c is a control character.如果 c 是控制字符,則為 true

isdigit(c)

true if c is a digit.如果 c 是數字,則為 true。

isgraph(c)

true if c is not a space but is printable.如果 c 不是空格,但可打印,則為 true。

islower(c)

true if c is a lowercase letter.如果 c 是小寫字母,則為 true。

isprint(c)

True if c is a printable character.如果 c 是可打印的字符,則為 true。

【注意:可打印的字符是指那些可以表示的字符】

ispunct(c)

True if c is a punctuation character.如果 c 是標點符號,則 true。

【注意:標點符號則是除了數字、字母或(可打印的)空白字符(如空格)以外的其他可打印字符】

isspace(c)

true if c is whitespace.如果 c 是空白字符,則為 true。

【注意:空白字符則是空格、制表符、垂直制表符、回車符、換行符和進紙符中的任意一種】

isupper(c)

True if c is an uppercase letter.如果 c 是大寫字母,則 true。

isxdigit(c) 

true if c is a hexadecimal digit.如果是 c 十六進制數,則為 true。

tolower(c) 

If c is an uppercase letter, returns its lowercase equivalent; otherwise returns c unchanged.如果 c 大寫字母,返回其小寫字母形式,否則直接返回 c。

toupper(c)

If c is a lowercase letter, returns its uppercase equivalent; otherwise returns c unchanged.如果 c 是小寫字母,則返回其大寫字母形式,否則直接返回 c。

【注意:ctype.h是定義在C標准庫中的頭文件,cctype 其實就是利用了 C 標准庫函數。C 標准庫頭文件命名形式為 name 而 C++ 版本則命名為 cname ,少了后綴,.h而在頭文件名前加了 c 表示這個頭文件源自 C 標准庫。因此,cctype 與 ctype.h 文件的內容是一樣的,只是采用了更適合 C++程序的形式。特別地,cname 頭文件中定義的名字都定義在命名空間 std 內,而 .h 版本中的名字卻不是這樣。通常,C++ 程序中應采用 cname 這種頭文件的版本,而不采用 name.h 版本,這樣,標准庫中的名字在命名空間 std 中保持一致。使用 .h 版本會給程序員帶來負擔,因為他們必須記得哪些標准庫名字是從 C 繼承來的,而哪些是 C++ 所特有的。】

 

字符串操作

以下總結更新於2014.10.01,來源於經典教材。

其中:s和str是字符串string,ca是一個字符數組,str_ca是一個字符串或者一個字符數組,str_ca_ch是一個字符串、字符數組或一個字符,ch是一個字符,n、n1、n2、pos1、pos2是整數。

 

長度操作

s.capacity()

返回s獲取的存儲容量;

 

s.size()/s.length()

返回s的長度;

s.empty()

如果s沒有包含字符則返回true,否則返回false;

s.max_size()

返回s可能的最大長度; 

 

編輯操作

s.append(str_ca)

將str_ca添加到s的結尾,返回s;

s.append(ca, n)

將ca的前n個字符添加到s的結尾,返回s;

s.append(n, ch)

將ch的n份拷貝添加到s的結尾,返回s;

 

s.insert(pos, str)

將str的拷貝插入到s的pos位置,返回s;

s.insert(pos1, str, pos2, n)

將str中從pos2位置開始的n個字符插入到s的pos1位置,返回s;【如果n大於str的長度,不會有問題,沒有溢出錯誤,只會復制到str的末尾】

s.insert(pos, ca, n)

將ca的前n個字符插入到s的pos位置,如果n被省略,則插入ca中所有的字符到pos位置,返回s;

s.insert(pos, n, ch)

將字符ch的n個拷貝插入到s的pos位置,返回s;

 

s.erase(pos, n)

刪除s中從pos開始的n個字符(默認pos為0),返回s;

s.replace(pos1, n1, str)

將s中pos1位置開始的長度為n1的字符串替換為str【如果n1太大,從pos到s結尾的所有字符將被替換】,返回s;

 

s.replace(pos1, n1, ca, n2)

和上面一樣,只不過取ca的前n2個字符,返回s;

 

s.swap(str)/swap(s, str)

交換s和str的內容分,返回為void;

 

復制操作

支持+  +=操作符。

s.assign(str_ca)

將str_ca的一份拷貝賦予s,返回s;

s.assign(ca, n)

將ca的前n個字符構成的字符串賦予s,返回s;

s.assign(n, ch)

將n個ch組成的字符串賦予s,返回s;

s.substr(pos, n)

返回s中從pos(默認為0)開始的,有n個字符組成的s的子串的拷貝;

 

查找操作

s.find(str_ca_ch, pos)

返回s中第一個大於等於pos的位置,並且從這個位置的下一個字符開始s中字符和str_ca_ch中相應字符匹配。如果沒有這樣的位置則返回npos,pos默認為0

s.find_first_of(str_ca_ch, pos)

返回s中大於等於pos的第一個和str_ca_ch中任意字符匹配的字符的位置,如果沒有這樣的位置則返回npos,pos的默認值為0

 

s.find_first_not_of(str_ca_ch, pos)

返回s中大於等於pos的第一個和str_ca_ch中任意字符都不匹配的字符的位置,如果沒有這樣的位置則返回npos,pos的默認值為0

s.find_last_of(str_ca_ch, pos)

返回s中小於等於pos的最大的一個和str_ca_ch中任意字符匹配的字符的位置,如果沒有這樣的位置則返回npos,pos的默認值為0

s.find_last_not(str_ca_ch, pos)

返回s中小於等於pos的最大的一個和str_ca_ch中任意字符都不匹配的字符的位置,如果沒有這樣的位置則返回npos,pos的默認值為0

s.rfind(str_ca_ch, pos)

返回s中最后一個小於等於pos的位置,並且從這個位置開始的str_ca_ch.size()個字符和str_ca_ch中相應的字符匹配。如果沒有這樣的位置則返回npos,pos默認為npos

比較操作

支持上述 <、<=、>、>=、==、!=操作符。

s.compare(str_ca)

返回值為正、0、負

 

string和C風格字符串的轉換

s.c_str()

返回一個常字符數組,這個數組包含存儲在s中字符,以一個空字符結束;

 

s.data()

返回一個常字符數組,這個數組包含存儲在s中字符,但沒有以空字符結束;

 

s.copy(charArray, pos, n)

將charArray替換為s中從pos開始的n個字符,如果pos被省略了,即從0開始,如果n太大,那么拷貝字符直到s結束,返回最終拷貝的字符個數。

 

備注:data()和c_str()都可以被用來從一個文件名中提取open操作所需要的字符數組。

 

#include <iostream>

#include <string>

#include <vector>

using std::cin; using std::cout; using std::endl; using std::string; using std::vector;

 

string deal_word(string word)

{

// 使用c++11 auto 語句 以及range for 語句

for(auto &c : word)

{

if (not ispunct(c))

{

c = toupper(c); //連接非標點字符到字符串

}

else

{

word.erase(word.size()-1, 1); //只能刪除最后一個標點符號。有局限性!

}

}

return word;

}

 

string deal_word2(string word)

{

// 使用下標及c++11 decltype

    for (decltype(word.size()) index = 0; index != word.size(); ++index)

    {

    if (not ispunct(word[index]))

{

    word[index] = toupper(word[index]);

}

    else

    {

    word.erase(index, 1); // 刪除指定位置上的某一個字符,在此為標點

    index -= 1; //保證下標不越界!重要!

    }

    }

    return word;

}

 

int main()

{

string word; // 緩存輸入的單詞

vector<string> text; // empty vector

cout<<"Please input the text:"<<endl; //提示輸入

while (std::cin >> word and word != "INPUTOVER") // INPUTOVER 用於標示輸入結束,也可以ctrl + z停止輸入

{

        word = deal_word(word); // 單詞處理

text.push_back(word); // append word to text

}

for(std::vector<int>::size_type ix =0, j = 0; ix != text.size(); ++ix, ++j)

{

if (j==8) // 8個單詞一行

{

cout<<endl; //換行

j = 0; //重新計數

}

    cout<<text[ix]<<" "; //加空格!

}

    return 0;

}

改寫了兩種處理單詞的方法。使用了c++11中的新特性!

 

str.erase()方法:

 

1、erase(pos, n); 刪除從pos開始的n個字符,比如erase(0,1)就是刪除第一個字符

2、erase(position); 刪除position處的一個字符(position是個string類型的迭代器)

3、erase(first, last); 刪除從first到last之間的字符(first和last都是迭代器)

c++中c_str()的用法詳解

 

//標准庫的string類提供了三個成員函數來從一個string得到c類型的字符數組 //主要介紹c_str //c_str():生成一個const char*指針,指向以空字符終止的數組。 //這個數組應該是string類內部的數組
#include <iostream>
//需要包含cstring的字符串
#include <cstring>
using namespace std; int main() { //string-->char* //c_str()函數返回一個指向正規C字符串的指針, 內容與本string串相同 //這個數組的數據是臨時的,當有一個改變這些數據的成員函數被調用后,其中的數據就會失效。 //因此要么現用先轉換,要么把它的數據復制到用戶自己可以管理的內存中
    const char *c; string s = "1234"; c = s.c_str(); cout<<c<<endl; s = "abcde"; cout<<c<<endl; }

結果是:

 

 上面如果繼續用c指針的話,導致的錯誤將是不可想象的。就如:1234變為abcde

其實上面的c = s.c_str(); 不是一個好習慣。既然c指針指向的內容容易失效,我們就應該按照上面的方法,那怎么把數據復制出來呢?這就要用到strcpy等函數(推薦)。

 

//標准庫的string類提供了三個成員函數來從一個string得到c類型的字符數組
//主要介紹c_str
//c_str():生成一個const char*指針,指向以空字符終止的數組。
//這個數組應該是string類內部的數組
#include <iostream>
//需要包含cstring的字符串
#include <cstring>
using namespace std;
 
int main()
{
    //更好的方法是將string數組中的內容復制出來 所以會用到strcpy()這個函數
    char *c = new char[20];
    string s = "1234";
    // c_str()返回一個客戶程序可讀不可改的指向字符數組的指針,不需要手動釋放或刪除這個指針。
    strcpy(c,s.c_str());
    cout<<c<<endl;
    s = "abcd";
    cout<<c<<endl; 

}參考:https://www.cnblogs.com/findumars/p/6353621.html

vector<string> split(string &s, string &delim, bool removeEmpty = false, bool fullMatch = false) { vector<string> result; string::size_type start = 0, skip = 1; // 使用整個字符串進行查找,之后會直接跳過整個子字符串if (fullMatch) { skip = delim.length(); } while (start != string::npos) { // 從start位置開始查找子字符串delim第一次出現的位置string::size_type finsh = s.find(delim, start); if (skip == 0) { finsh = string::npos; } // 從start開始到(finsh - start)處獲得子字符串// 獲得匹配字符串之前的字符串string token = s.substr(start, finsh - start); // 對token進行判斷並決定是否移除空if (!(removeEmpty && token.empty())) { // 將匹配字符串之前的字符串放進向量中 result.push_back(token); } // 判斷此時是否到了原字符串的末尾if ((start = finsh) != string::npos) { // 將子字符串放進向量中,是為了保證原字符串的字符不丟失 result.push_back(delim); // 將查找位置向前移動skip個位置 start = start + skip; } } return result; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM