Cpp知識點系列-字符串

君匡 發佈 2022-12-04T16:12:23.536311+00:00

前言記錄一些對字符串的理解。接下來我所說的都是依賴於頭文件<string>的。理論什麼是字符串字符串實際上是使用 null 字符 '\0' 終止的一維字符數組。因此,一個以 null 結尾的字符串,包含了組成字符串的字符。

前言

記錄一些對字符串的理解。

接下來我所說的都是依賴於頭文件<string>的。

理論

什麼是字符串

字符串實際上是使用 null 字符 '\0' 終止的一維字符數組。因此,一個以 null 結尾的字符串,包含了組成字符串的字符。

string與cstring有什麼區別

<string>是C++標準庫頭文件,包含了擬容器class std::string的聲明(不過class string事實上只是basic_string<char>typedef),用於字符串操作。

<cstring>是C標準庫頭文件<string.h>的C++標準庫版本,包含了C風格字符串(NULL即'\0'結尾字符串)相關的一些類型和函數的聲明,例如strcmp、strchr、strstr等。

兩者最大區別在於:

  • string是新標準,定義了namespace std;cstring定義中包含的是string.h
  • string中可以進行+ = += >等運算,而cstring中不能進行相關運算。

什麼是string類型的疊代器

聲明一個string類中特有的類型size_type變量,名稱為position

string::size_type position;

疊代器是一個變量,相當於容器和操縱容器的算法之間的中介 , 實在理解困難認為是個特別的int下標也可以。

疊代器可以指向容器中的某個元素,通過疊代器就可以讀寫它指向的元素。從這一點上看,疊代器和指針類似。

//從類名獲取該對象
string::npos;
//從對象獲取該對象
string tempstr;
tempstr.npos;

這個npos是個特別的疊代器對象,可以理解成為string類型中特別的NULL,如果查找失敗或者遍歷完畢之後疊代器的值就是這個.

操作

首先引入頭文件,並且在命名空間中使用。

#include<string>
using namespace std;

Strings常用方法

方法名作用Operators操作符,可以用 ==, >, <, >=, <=, and !=比較字符串. 可以用 + 或者 += 操作符連接兩個字符串, 並且可以用[]獲取特定的字符append()在字符串的末尾添加文本(就是+=)compare()比較兩個字符串empty()如果字符串為空,返回真erase()刪除字符insert()插入字符length()返回字符串的長度Replace()替換字符size()返回字符串中字符的數量(結果等價於length)substr()返回某個子字符串swap()交換兩個字符串的內容

如果可以使用自帶的方法去實現的話自然是比較好的,但是如果只能夠針對部分字符進行複雜變化的話,就需要轉化成為char*類型的數組

構造法

平常更多是用等號直接賦值,如果要求字符串中間有結尾符可以這樣聲明。

void stringTestConstruct() {
    string str =string("12345 \0 54321", 13);//不等價於str="12345 \0 54321";
    cout << str<<endl;
    string str1 = "12345 \0 54321";
    cout << str1;
}


void stringTestAppend() {
    string str = "Hello";
    str.append(3, '!');//等價於str+="!!!" ;
    cout << str;
}


初學時,沒考慮太多,後來才發現在添加'\0'字符時有奇效。

void stringTestAppend2() {
    string str="abc";
    str.append("\0 def",5);//等價於 str =string("abc\0 def", 8);
    cout << str;
}

image-20221108135309114

compare

compare()比較時逐字符比較的,一旦能比較出結果,就不再比較了。

雖然有多個重載,但是只需要理解,在this字符串與傳入的比較字符串str一部分(至於是哪一部分用起點和長度來評定)之間進行的比較即可。

 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_type length2 );

在str之前的參數是修飾this,在str之後的參數是修飾str的

返回值情況小於零this < str(自己弱小就認''負'')零this == str大於零this > str(自己強大就囂''正'')

void stringTestCompare() {
    string s1 = "abandon";
    string s2 = "about";
    int b = s1.compare(s2);//直接比較,s1小於s2,故返回-1
    int c = s1.compare(2, 4, s2);//s1下標為2的字符a開始的4個字符ando和s2進行比較。ando大於s2故返回1
    cout << c << endl;
    int d = s1.compare(2, 4, s2, 1, 3);
    cout << d << endl;//s1下標為2的字符a開始的4個字符ando和s2下標為1的字符b開始的3個字符bou比較。前者小,故返回-1。
    string s3 = "abc";
    string s4 = "abc";
    int e = s3.compare(s4);//相等返回0
    cout << e << endl;
}

erase

也有參數為疊代器的函數,在下面介紹。

basic_string &erase( size_type index = 0, size_type num = npos );
  • 刪除從index索引開始的num個字符, 返回刪減後的字符串。其中index默認從0開始,num默認是最大值。
void stringTestErase() {
    string s("1234567890123456789012345");//總共25個字符
    cout << s << endl;
    cout << s.erase(10, 6) << endl;//從下標第10的字符開始刪除,一共刪除6個。
    cout << s.erase(10) << endl;//刪除下標為10的字符及之後的 ==保留下標小於10的字符
    cout << s.erase();//清空字符串
}

image-20201126200020627

insert

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 );
  • 在字符串的位置index插入字符串str;
  • 在字符串的位置index插入字符串str的子串(從index2開始,長num個字符);
  • 在字符串的位置index插入字符串str的num個字符;
  • 在字符串的位置index插入num個字符ch的拷貝字符串。

其實理解起來就是,在本字符串的index位置,插入參數中的字符串的一部分(至於是哪一部分

用起點和長度來評定)。

void stringTestInsert() {
    string str = "abc";
    str.insert(1, "123");
    /*在下標為1的位置,插入字符串123全部*/
    cout << str << endl;
    str = "abc";
    str.insert(1, "123", 1, 1);
    /*在下標為1的位置,插入字符串123的一部分,並且從下標1開始,長度為1的一段*/
    cout << str << endl;
    str = "abc";
    str.insert(1, "123", 2);
    /*在下標為1的位置,插入字符串123的一部分,並且從下標0開始,長度為2的一段*/
    cout << str << endl;
    str = "abc";
    str.insert(1, 2, 'z');
    /*在下標為1的位置,插入2個字符z*/
    cout << str;
}

image-20221108141757159

length

其實不用糾結在獲取長度的時候是用size還是length,至少在GCC6的情況下,返回的都是同一個欄位_M_string_length

void stringTestLength() {
    //其實後面都是返回的同一個欄位_M_string_length。
    string s("1234567890123456789012345");//總共25個字符
    cout << s.size()  << endl;//輸出25
    cout << s.length()  << endl;//輸出25
}

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

其實理解起來就是,在將本字符串的index位置長度為num的字符串,替換成參數中的字符串的一部分(至於是哪一部分用起點和長度來評定)。

一般用起來的時候,更多是和find函數一起,實現查找替換的作用。然而find函數是涉及到了疊代器,所以這裡只是簡單示例一下。有興趣可以直接下翻。

void stringTestReplace() {
    string str="1234567890";
    str.replace(0,9,"ABC");
    /*把下標從0開始、長度為2的一段字符串,替換為ABC*/
    cout << str<<endl;
    str="1234567890";
    str.replace(str.find('8'),3,"ABC");
    /*把從字符8開始、長度為2的一段字符串,替換為ABC*/
    cout << str;
}

substr

  basic_string substr( size_type index, size_type num = npos ); 

截取本字符串從index開始之後的num個字符,沒錯就是跟上面的刪除差不多!

特別的,用程序形象的看一眼效果:

void stringTestSubstr() {
    string s("123456789012345678901234567890");
    cout << s << endl;
    printf("%30s\n", s.substr(21).c_str());
    cout << s.erase(21) << endl;
}

image-20201126222643653

swap

 void swap( basic_string &str );

這個函數的作用主要就是將兩個字符串的全部元素進行交換。

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

image-20201126222955616

如果只是針對部分元素,可以用insertreplace進行操作。

轉char*

方法名作用c_str()將字符串以C字符數組的形式返回copy(*str, num, index )將內容複製為一個字符數組data()返回內容的字符數組形式

c_str( )

 const char *c_str();

返回一個const臨時指針,指向以\0結尾的字符數組,應該使用strcpy()函數等來操作。

void stringTestC_str() {
    //數組
    char c[20];
    string s="1234";
    strcpy(c,s.c_str());//注意strcpy函數是在cstring頭文件中的
    cout<<c;
    //指針
    string str = "hello";
    const char* p1 = str.c_str();//加const
    char * p2=(char*)str.c_str();//或者是強制轉換
}

data( )

const char *data();

照常來說是字符串內容外,**不附加結束字符'\0'**。

有資料顯示,兩者是應該有區別的c_str()有結束符,而data()沒有結束符。

image-20201126172130028

因為我這個編譯環境的問題,在dev的環境中兩個方法,其實都是返回的_M_data()方法而已的。

copy(*str,num,index )

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

size_type copy( char *str, size_type num, size_type index );

由於還需要手動加結束符

void stringTestCopy() {
    string str = "hmmm";
    char p[10];
    str.copy(p, 3, 0);
    /*把從0開始、長度為3的字符串,複製到字符數組p之中*/
    p[3] = '\0';//注意手動加結束符!!!
    cout << p;
}

疊代器

方法名作用begin()返回一個疊代器,指向第一個字符end()返回一個疊代器,指向字符串的末尾。(最後一個字符的下一個位置)erase()刪除字符find()在字符串中查找字符find_first_of()查找第一個與value中的某值相等的字符find_first_not_of()查找第一個與value中的所有值都不相等的字符find_last_of()查找最後一個與value中的某值相等的字符find_last_not_of()查找最後一個與value中的所有值都不相等的字符get_allocator()返回配置器insert()插入字符rbegin()返回一個逆向疊代器,指向最後一個字符rend()返回一個逆向疊代器,指向第一個元素的前一個位置replace()替換字符rfind()查找最後一個與value相等的字符(逆向查找)

find

把str的全部字符當作整體進行查找.

 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 );
  • 返回str在字符串中第一次出現的位置(從index開始查找)如果沒找到則返回string::npos
  • 返回str在字符串中第一次出現的位置(從index開始查找,長度為length)。如果沒找到就返回string::npos
  • 返回字符ch在字符串中第一次出現的位置(從index開始查找)。如果沒找到就返回string::npos

代碼:

void stringiteratorTestFind() {
    string s("qwe123qwee123qweqwe1");
    string flag = "123";
    string::size_type position = 0;
    int i = 1;
    while ((position = s.find(flag, position)) != string::npos) {
        cout << "position  " << i << " : " << position << endl;
        position++;
        i++;
    }
}

image-20201126230709115

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的即可。

特別注意

find_first_of 函數和find函數最大的區別就是,如果在str1中查找str2時,如果str1中含有str2中的任何字符,就會查找成功,而find則只有全部相同才會查找成功.

比如:

void stringIteratorTestFind_first_of () {
    string s("qwe123qwee123qweqwe1");
    string flag="123";
    string::size_type position=0;
    int i=1;
    while((position=s.find_first_of(flag,position))!=string::npos) {
        cout<<"第"<<i<<"次匹配 : "<<position<<endl;
        position++;
        i++;
    }
}

與上面的例子區別只是更換了一個函數而已,但是結果完全不同。

image-20221108150441682

至於其他的not,last的變名函數則是顧名思義即可。

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

當正向查找與反向查找得到的位置不相同說明子串不唯一。

erase

 iterator erase( iterator pos );
 iterator erase( iterator start, iterator end );
  • 刪除pos指向的字符, 返回指向下一個字符的疊代器,
  • 刪除從start到end的所有字符, 返回一個疊代器,指向被刪除的最後一個字符的下一個位置

insert

 iterator insert( iterator i, const char &ch );
 void insert( iterator i, size_type num, const char &ch );
 void insert( iterator i, iterator start, iterator end );
  • 在疊代器i表示的位置前面插入一個字符ch,
  • 在疊代器i表示的位置前面插入num個字符ch的拷貝,
  • 在疊代器i表示的位置前面插入一段字符,從start開始,以end結束.

replace

 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 );
  • 用str中的字符替換本字符串中的字符,疊代器start和end指示範圍
  • 用str中的num個字符替換本字符串中的內容,疊代器start和end指示範圍,
  • 用num個ch字符替換本字符串中的內容,疊代器start和end指示範圍.

感謝

參考書籍《C++語言程序設計(第4版)》(鄭莉,董淵)

C++string的compare()比較函數

感謝現在的好奇,為了能成為更好的自己。

關鍵字:

男生聞到⋯90%再累都會想"起來"!

2021-10-13T07:55:51.105254+00:00

用香味喚醒熱戀

莉莉我身邊超多朋友用完都說:
【男生聞到⋯90%再累都會想"起來"】(妳們懂的😳)
 
最近跟他吵架,兩個人都非常不!開!心!
唉⋯在一起久了就是這樣,吵架時兩個都無力再去討好對方,

明明每天一起吃飯,餐桌上只有餐具碰撞的聲音,

沒有人想主動開口說話,吃飽就默默自己收拾離開⋯
 
到現在已經一個多月沒講話了『我真的想和好⋯』
但,又不想要先低頭
突然想起之前那罐閨蜜送我的“韓妞沐浴露”

 


說可以用香味喚醒熱戀!
https://www.cashin.tw/product/000000000034855 

因為嗅覺是無法關閉的器官,氣味會直達大腦邊緣系統,

刺激情緒感官,挑起一些感受😳

 


我覺得味道不會太重是淡淡的,蠻香的~~
之後趕緊假睡,後來他進來看到我先愣了一下,

他說怎麼這麼香,手就開始⋯後續就不說了🥰

久旱逢甘霖,不知道是不是被味道刺激,變得相當賣力,

但我很喜歡😳熟悉的甜蜜終於回來了!
早上超累的,看他倒是神情氣爽,看樣子有好好釋放到哈哈!
還說今晚想洗泡泡浴❤⇢https://www.cashin.tw/product/000000000034855

 

商品資訊

 ▼韓妞維持熱戀的秘訣大公開!!▼  

⇢用香味喚醒他的激情 不自覺一直想妳

 ﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍

\穿在身上的香水 純潔果香沐浴露誕生/

 榮獲韓國男性最有好感的香味 NO.1🥇

 

https://www.cashin.tw/product/000000000034855