[学习笔记]字符串的一些基本操作
字符串有很多操作,目前先不讲什么\(KMP\),\(AC\)自动机之类的高端算法。我感觉字符串的操作对于\(OIer\)们比较薄弱,特别是转\(C++\)的\(P\)党们
便于本文阅读,开头省略以下代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
并且考虑到阅读体验,输入输出将不用\(latex\)
字符串的输入输出的一些常见误区
\(string\)类型一般都是用\(cin\)读入。
\(char\)类型用\(cin\),\(scanf\)或者\(sscanf\)读入
一般字符串的题目都是模拟题,所以不用怕\(cin\)超时
1、\(cin\) 作用:读到空格,\(Tab\),回车就结束读入
\(char\)版:
int main()
{
char s[20];
cin>>s;
cout<<s<<endl;
return 0;
}
\(string\)版:
int main()
{
string s;
cin>>s;
cout<<s<<endl;
return 0;
}
\(Input\):abc def
\(Output\):abc
2、\(scanf\) 作用:同\(cin\)
\(char\)版:
int main()
{
char s[20];
scanf("%s",s);
printf("%s\n",s);
return 0;
}
\(Input\):abc def
\(Output\):abc
3、\(getline\) 作用:读入整行字符串,碰到换行退出
\(string\)版:
int main()
{
string s;
getline(cin,s);
cout<<s<<endl;
return 0;
}
\(Input\):abc def
\(Output\):abc def
4、\(cin.get\) 作用:读入单个字符,类型必须是\(char\)
int main()
{
char s;
s=cin.get();
cout<<s<<endl;
return 0;
}
\(Input\):abc def
\(Output\):a
5、\(getchar\) 作用:读入单个字符,类型必须是\(char\)
int main()
{
char s;
s=getchar();
cout<<s<<endl;
return 0;
}
\(Input\):abc def
\(Output\):a
输出有几种方式,\(cout\),\(printf\),\(putchar\),不过我觉得\(gets\)和\(puts\)要尽量少用,有些题目用\(gets\)会因为\(Linux\)的一些原因导致程序\(WA\)
顺带提一句,除\(puts\)会输出自动换行,其他三种输出方式不会自动换行
正文
笔者罗列了一下字符串的基本操作:
字符串操作:赋值,复制,连接,比较,清空
字符串性质:求串长,求子串,查找子串,删除,替换,插入
字符串状态:判定串是否为空
那么我们从字符串的操作讲起吧
1、赋值
(1) \(=\)
单个字符用单引号'',多个字符用双引号""
int main()
{
char s1[20]="What?!",s2='W';
cout<<s1<<" ";
cout<<s2<<endl;
return 0;
}
\(Output\): What?! W
(2)\(push_back\)
这是\(string\)特有的,因为直接赋值单字符''会\(CE\),用法即在字符串末尾添加一个字符
int main()
{
string s;
s.push_back('W');
cout<<s<<endl;
return 0;
}
\(Output\):W
(3) \(memset\)
memset(s,c,len) 将字符串\(s\)前\(len\)的字符初始化为\(char\)类型\(c\)
int main()
{
char s[20];
memset(s,'0',sizeof(s)+1);//不+1结尾会输出一个问号
cout<<s<<endl;
return 0;
}
\(Output\):0000000000000000000
2、复制
\(char\)类型:
(1) \(memcpy\)
memcpy(s1,s2,len) 将\(s2\)复制\(len\)长度到\(s1\)
int main()
{
char s1[20],s2[20]="What?!",s3[20]="Aha!";
memcpy(s1,s2,strlen(s2)+1);//将s2复制到s1
cout<<s1<<" ";
memcpy(&s1,&s3,sizeof(s3));;//将s3复制到s1
cout<<s1<<endl;
return 0;
}
\(Output\): What?! Aha!
(2) \(strcpy\)
strcpy(s1,s2) 将\(s2\)复制到\(s1\)上
int main()
{
char s1[20],s2[20]="What?!";
strcpy(s1,s2);//将s2复制到s1
cout<<s1<<" ";
strcpy(s1,"Aha!");//将"Aha!"复制到s1
cout<<s1<<endl;
return 0;
}
\(Output\): What?! Aha!
(3)\(strncpy\)
strncpy(s1,s2,len) 将\(s2\)复制\(len\)长度到\(s1\)
int main()
{
char s1[20]={0},s2[20]={0},s3[20]="What?!";//这里不初始化会出现奇怪的东西
strncpy(s1,s3,sizeof(s3));//将s3复制到s1
cout<<s1<<" ";
strncpy(s2,s3,4);//将s3开始的4个字符复制到s2
cout<<s2<<endl;
return 0;
}
\(Output\): What?! Aha!
\(string\)类型:
(1) \(=\)
直接等于另一个字符串
int main()
{
string s1,s2="What?!";
s1=s2;
cout<<s1<<endl;
return 0;
}
\(Output\):What?!
(2) \(copy\)
s1.copy(s,len,s) 复制\(s1\)第\(l\)个位置,长度为\(len\)到字符串\(s\),但是\(s\)是\(char\)类型
int main()
{
string s1="Code is King";
char s[6];s1.copy(s,7,5);
cout<<s<<endl;
return 0;
}
如果定义字符数组大于所要\(copy\)的长度,会出现奇怪的东西,所以要手动算长度
3、连接
\(char\)类型:
(1)\(strcat\)
strcat(s1,s2) 在\(s1\)后拼接\(s2\)
int main()
{
char s1[20]="Code is",s2[20]=" King";
strcat(s1,s2);//在s1后拼接s2
cout<<s1<<endl;
return 0;
}
\(Output\):Code is King
(2)\(strncat\)
strncat(s1,s2,len) 在\(s1\)后面拼接\(s2\)的前\(len\)个字符
int main()
{
char s1[20]="Code is",s2[20]=" King Code";
strncat(s1,s2,5);//在s1后面接上s2开始的5个字符
cout<<s1<<endl;
return 0;
}
\(Output\):Code is King
\(string\)类型:
(1) +=
由于\(string\)里面有\(operator\),所以直接\(+=\)就行了
int main()
{
string s1="Code is",s2=" King";
s1+=s2;//直接接上
cout<<s1<<endl;
return 0;
}
\(Output\):Code is King
4、比较
\(char\)类型:
(1) \(strcmp\)
strcmp(s1,s2) 若s1>s2,返回一个正数;若s1==s2,返回\(0\),若s1<s2 返回一个负数
怎么判定一个串比较和另一个串的大小呢?\(C++\)是比较第一次失配时两个字符\(ASCLL\)码的大小,一个串是另一个串的前缀,那么另一个串大
int main()
{
char s1[20]="Code is King";
char s2[20]="Code is King";
char s3[20]="Code is Queen";
cout<<strcmp(s1,s2)<<" ";//比较大小
cout<<strcmp(s1,s3)<<endl;
return 0;
}
\(Output\):0 -1
(2) \(strncmp\)
strncmp(s1,s2,len) 比较\(s1\)和\(s2\)的前\(len\)个字符,若s1>s2,返回一个正数;若s1==s2,返回\(0\),若s1<s2 返回一个负数
int main()
{
char s1[20]="Code is King";
char s2[20]="Code is Queen";
cout<<strncmp(s1,s2,8)<<" ";//比较s1和s2的前8个字符
return 0;
}
\(Output\):0
\(string\)类型
(1) \(>\ =\ <\)
原理同\(string\)中的\(=\),比较方式同\(strcmp\)
int main()
{
string s1="Code is King";
string s2="Code is King";
string s3="Code is Queen";
if(s1==s2) cout<<0<<" ";//直接比较
else cout<<-1<<" ";
if(s2==s3) cout<<0<<endl;
else cout<<-1<<endl;
return 0;
}
\(Output\):0 -1
5、清空
\(char\)类型: 可以直接一位一位赋值,或者直接\(memset\),用法略
\(string\)类型:
(1) \(clear\)
s.clear() 清空原串
int main()
{
string s="Code is King";
s.clear();//清空
cout<<s<<endl;
return 0;
}
\(Output\):啥都不输出
(2) 直接等于一个空串,用法略
接下来就是字符串性质
1、求串长
\(char\)类型:
(1) \(strlen\)
strlen(s) 返回字符串\(s\)的长度
int main()
{
char s[20]="Code is King";
cout<<strlen(s)<<endl;//求s的长度
return 0;
}
\(Output\):12
\(string\)类型:
(1) \(s.length\)
s.length() 返回字符串\(s\)的长度
int main()
{
string s="Code is King";
cout<<s.length()<<endl;//求s的长度
return 0;
}
\(Output\):12
\(Tips\):如果你平常用这种方法写输出请改一下
for(int i=0;i<strlen(s);i++)
cout<<s[i];
cout<<endl;
因为每一次都要算一个\(strlen\),所以复杂度成为了\(O(n^2)\)
2、求子串
\(char\)类型:直接\(strnpy\),用法略
\(string\)类型:
(1) \(s.substr\)
s,substr(l,len) 复制串\(s\)从第\(l\)个字符开始\(len\)长度的串
s.substr(l) 复制串\(s\)到末尾
int main()
{
string s1="Code is King";
string s2=s1.substr(5,7);//复制从第5个字符开始的7个字符
string s3=s1.substr(5);//复制从第5个字符开始直到末尾
cout<<s2<<" ";
cout<<s3<<endl;
return 0;
}
\(Output\):is King is King
3、查找子串
\(char\)类型
(1) \(strstr\)
strstr(s1,s2) 查找\(s2\)\(s1\)第一次中指针地址,若找不到,指针地址为\(end\)
int main()
{
char s[20]="Code is King";
char *p=strstr(s,"is");//在s中查找is并返回指针
cout<<p<<endl;
return 0;
}
\(Output\):is King
(2) \(strnstr\) 反向查找\(s2\)在\(s1\)第一次的指针地址,若找不到,指针地址为\(end\),用法略
\(string\)类型:
(1) \(find\)
s.find(s1) 查找串\(s1在串\)s\(中\)第一次出现的位置,若找不到,值为\(s.end()\)
int main()
{
string s="Code is King";
int find=s.find("is");//查找s中的is
cout<<find<<endl;
return 0;
}
\(Output\):5
(2) \(rfind\)
s.rfind(s1) 反向查找串\(s1在串\)s\(中\)第一次出现的位置,若找不到,值为\(s.end()\)
int main()
{
string s="Code is King";
int find=s.rfind("is");//反向查找is
cout<<find<<endl;
return 0;
}
\(Output\):5
4、删除
\(string\)类型:
(1) \(erase\)
s,erase(l,len) 删除串\(s\)从第\(l\)个字符开始\(len\)长度的串
s.erase(l) 删除第\(l\)个字符
s.erase(l,r) 删除\([l,r]\)区间内的字符
int main()
{
string s="This is an example sentence.";
cout<<s<<'\n'; //This is a example sentence.
s.erase(10,8);
cout<<s<<'\n'; //This is an sentence.
s.erase(s.begin()+9);
cout<<s<<'\n'; //This is a sentence.
s.erase(s.begin()+5, s.end()-9);
cout<<s<<'\n'; //This sentence.
return 0;
}
\(Output\):
This is a example sentence.
This is an sentence.
This is a sentence.
This sentence.
\((Code\ By\ Reference\ C++)\)
5、替换
\(string\)类型:
(1) \(replace\)
s.replace(l,len,s1) 将串\(s\)中第\(l\)个字符开始\(len\)长度替换为串\(s1\)
s.replace(l1,len1,s1,l2,len2) 将串\(s\)中第\(l1\)个字符开始\(len1\)长度替换为串\(s1\)中第\(l2\)个字符开始\(len2\)长度
s.replace(l1,len1,s1,len2) 将串\(s\)中第\(l1\)个字符开始\(len1\)长度替换为串\(s1\)前\(len2\)长度
s.replace(l1,len1,len2,c) 将串\(s\)中第\(l1\)个字符开始\(len1\)长度替换为\(len2\)个\(c\)字符 \(c\)是\(char\)类型
int main()
{
string base="this is a test sing.";
string s2="n example";
string s3="sample phrase";
string s4="useful.";
// Using positions:
sing s=base; // "this is a test sing."
s.replace(9,5,s2); // "this is an example sing." (1)
s.replace(19,6,s3,7,6); // "this is an example phrase." (2)
s.replace(8,10,"just a"); // "this is just a phrase." (3)
s.replace(8,6,"a shorty",7); // "this is a short phrase." (4)
s.replace(22,1,3,'!'); // "this is a short phrase!!!" (5)
// Using iterators:
s.replace(s.begin(),s.end()-3,s3); // "sample phrase!!!" (1)
s.replace(s.begin(),s.begin()+6,"replace"); // "replace phrase!!!" (3)
s.replace(s.begin()+8,s.begin()+14,"is coolness",7); // "replace is cool!!!" (4)
s.replace(s.begin()+12,s.end()-4,4,'o'); // "replace is cooool!!!" (5)
s.replace(s.begin()+11,s.end(),s4.begin(),s4.end());// "replace is useful." (6)
cout<<s<<endl;
return 0;
}
\(Output\):replace is useful
\((Code\ by\ Reference\ C++)\)
6、插入
\(string\)类型:
(1) \(insert\)
s.insert(l,s1) 将串\(s1\)插入到串\(s\)第\(l\)个字符后
s.insert(l1,s1,l2,len) 将串\(s1\)第\(l2\)个字符开始\(len\)长度插入到串\(s\)第\(l1\)个字符后
s.insert(l,s1,len) 将串\(s1\)前\(len\)个字符插入到串\(s\)第\(l\)个字符后
s.insert(l,len,c) 将串\(s\)第\(l\)个字符后插入\(len\)个\(c\)字符 \(c\)是\(char\)类型
int main()
{
string s="to be question";
string s2="the ";
string s3="or not to be";
string::iterator it;
s.insert(6,s2); // to be (the )question
s.insert(6,s3,3,4); // to be (not )the question
s.insert(10,"that is cool",8); // to be not (that is )the question
s.insert(10,"to be "); // to be not (to be )that is the question
s.insert(15,1,':'); // to be not to be(:) that is the question
it = s.insert(s.begin()+5,','); // to be(,) not to be: that is the question
s.insert(s.end(),3,'.'); // to be, not to be: that is the question(...)
s.insert(it+2,s3.begin(),s3.begin()+3); // (or )
cout<<s<<endl;
return 0;
}
\(Output\): to be, or not to be: that is the question...
\((Code\ by\ Reference\ C++)\)
最简单的字符串状态留在最后
1、是否为空
\(string\)类型:
(1) \(empty\)
s.empty() 判定串\(s\)是否为空串,是返回\(1\),不是返回\(0\)
int main()
{
string s1="Code",s2;
if(!s1.empty()) cout<<1<<" ";
else cout<<0<<" ";
if(!s2.empty()) cout<<1<<endl;
else cout<<0<<endl;
return 0;
}
\(Output\):1 0
当然\(string\)里面还有一些函数如\(append\),\(assign\),笔者就不在此赘笔了
参考网站: