串的处理

一,题目要求

题目描述

在实际的开发工作中,对字符串的处理是最常见的编程任务。本题目即是要求程序对用户输入的串进行处理。具体规则如下:

  1. 把每个单词的首字母变为大写。
  2. 把数字与字母之间用下划线字符(_)分开,使得更清晰
  3. 把单词中间有多个空格的调整为 1 个空格。

输入描述

用户输入的串中只有小写字母,空格和数字,不含其它的字母或符号。每个单词间由 1 个或多个空格分隔。假设用户输入的串长度不超过 200 个字符。

输出描述

输出处理好的字符串。

输入输出样例

示例

输入

1
you and me what cpp2005program

输出

1
You And Me What Cpp_2005_program

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

二,解题思路

1,对空格的处理

举个例子:

image-20230107133513189

比如在这里,我们要删除多余的空格,只保留一个空格

就是当i本身为空格时,将j指向i+1,删去j位置所在的空格,删除函数erase会自动返回j的下一个位置,用while循环判断直至j不是空格

2,对首字母大写的处理

我们可以发现除了第一个单词外,其他的首字母都出现在空格的后面,也就是我们在上面处理完空格之后的j处,变为大写即可

3,对下划线的处理

下划线出现在字母和数字之间,只有两种情况

image-20230107134316342

  • 左面是字母,右面是数字

假定我们当前的下标为i指向数字,现在指向2,那么i-1需要是字母a-z或A-Z

  • 右面是字母,左面是数字

假定我们当前的下标为i指向数字,现在指向5,那么i+1需要是字母a-z或A-Z

三,对应知识点

1,包含头文件的区分

  • #include <string.h>

    C语言的头文件,包含比如strcpy之类的字符串处理函数。注意C语言里没有string类的概念,不要弄混。

    不可以定义string s;可以用到strcpy等函数

  • #include <string>

    C++的头文件,包含std::string的定义,属于STL范畴

    可以定义string s;可以用到strcpy等函数

  • #include <cstring>

    C++版本的头文件,和C语言版本的<string.h>对应,将C语言的函数定义在std命名空间内。

    不可以定义string s;可以用到strcpy等函数

在此处我们选择

2,c++中如何读入字符串

#此部分参考:https://exp-blog.com/lang/cpp-de-liu-chong-chang-yong-shu-ru/

cin

用法1: 最基本,也是最常用的用法,输入一个数字或字符(不接受空字符作为字符输入,当输入字符为空字符时,会不断重复要求输入,直至输入字符非空后,通过回车结束输入)

1
cin>>a>>b;    // cin允许这种"连续输入"模式

用法2: 接受一个字符串,遇“空格”、“TAB”、“回车”都结束:

1
2
char a[20];
cin>>a;
cin.get()

用法1: cin.get(字符变量名) 可以用来接收字符:

1
ch=cin.get();    //或者cin.get(ch);

用法2: cin.get(字符数组名,串长) 用来接收一行字符串,可以接收空格:

1
2
char a[20];
cin.get(a,20);//最后一位'/0'

用法3: cin.get(无参数)

没有参数,主要是用于舍弃输入流中的不需要的字符,多用于舍弃前一次输入时放在输入缓冲区的回车。

cin.getline()

用法1: 接受一个字符串,可以接收空格并输出:

1
2
char m[20];
cin.getline(m,5);//其中最后一个为'\0'

用法2: 当用在多维数组中的时候,也可以用cin.getline(m[i],20)之类的用法:

1
2
3
4
5
char m[3][20];
for(int i=0;i<3;i++){
cout<<"\n请输入第"<<i+1<<"个字符串:"<<endl;
cin.getline(m[i],20);
}

注: cin.getline()功能的扩展说明
  cin.getline()实际上有三个参数,cin.getline(char对象地址,串长,’结束字符’)
  ① 当第三个参数省略时,系统默认为’\0’
  ② 如果把例子中cin.getline()改为cin.getline(m,5,’a’);
    当输入jlkjkljkl时,输出jklj ; 输入jkaljkljkl时,输出jk
  ③ cin.getline()至少要有前2个参数,且只能和char(或char*)定义的字符串地址搭配,不能和string定义的字符串地址搭配

getline()

接受一个字符串,可以接收空格并输出(需 #include ):

1
2
string str;
getline(cin,str);

注:
  ① getline()cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数。
  ② getline(cin,string对象地址) 中的字符串地址只能和string定义的字符串地址搭配,不能和char(或char*)定义的字符串地址搭配。这与cin.getline()相反。

gets()

用法1: 接受一个字符串,可以接收空格并输出(需 #include <string>):

1
2
char m[20];
gets(m); //不能写成m=gets();

注:gets(char对象地址)
  gets()只能和char(或char*)定义的字符串地址搭配,不能和string定义的字符串地址搭配

用法2: 类似cin.getline()里面的一个例子,gets()同样可以用在多维数组里面:

1
2
3
4
5
for(int i=0;i<3;i++)
{
cout<<"\n请输入第"<<i+1<<"个字符串:"<<endl;
gets(m[i]);
}
getchar()
1
ch=getchar();    //不能写成getchar(ch);

注: getchar()是C语言的函数,C++也可以兼容,但是尽量不用或少用

本题中,因为我们需要用到STL更方便地操作字符串,所以我们采取getline,同时不要忘记包含头文件#include <string>

1
2
string str;
getline(cin,str);

3,c++中的string库函数

#参考文章:http://snowline.info/STL_gen.htm

①说明和初值:
1
2
3
string str;
string str("abcdef");
string str="abcdef";
②串连接:

可以使用+或+=连接两个或多个字符串,这些字符串,可以是const char *char *或string型的。有多个串时,前两个串中必须有一个是string型的。

1
2
3
4
string str1, str2 ;
str1="abc";
str2 = str1+"def"+"ghi";
str1+="def"+"ghi";
③串查找:

string容器提供了多种查找方法,这里只介绍最简单的正反向查找。

1.正向查找:查找串中出现指定子串的位置,使用find()函数,第一个参数表示子串。返回一个整型值,表示出子串的位置。大于等于0时表示出现了子串,否则表示没有出现。

1
2
str = "abcdefgcd";
int n = str.find("cd");//2

2.反向查找:从后面开始,查找串中出现指定子串的位置,使用rfind()函数,第一个参数表示子串。返回一个整型值,表示出子串的位置。大于等于0时表示出现了子串,否则表示没有出现。

1
2
str = "abcdefgcd";
int n = str.rfind("cd");//7,返回的都是从前往后数的下标
④串替换:

把一个串中的子串,替换为另一个串,使用replace()函数,第一个参数是替换位置,第二参数是替换长度,第三个参数是替换子串。替换串和被替换的子串长度可以不等。

1
2
string str = "abcdefgcd";
cout<<str.replace(1,3,"hello");//ahelloefgcd
⑤串插入:

在串的中间插入一个子串,使用insert()函数,第一个参数是插入位置,第二个是插入子串。

1
2
string str = "abcdefgcd";
cout<<str.insert(1,"hello");//ahellobcdefgcd
⑥串删除:

在串的中间,删除若干个字符,使用erase()函数,第一个参数是删除位置,第二个参数是删除长度。

1
2
3
4
5
6
7
string str = "abcdefgcd";
cout<<str.erase(1,3);//aefgcd

//编程中最常见的是和迭代器结合,用于删除指定位置字符
string str = "abcdefgcd";
str.erase(str.begin()+3);
cout<<str;//abcefgcd

注意:串的替换,插入,删除操作中,操作位置必须是0到字串长度的范围之内,超过这个范围,将会引起异常

⑦取子串操作:

从一个串中取子串的操作,使用substr()函数,第一个参数表示开始位置,第二个参数表示取的长度。如果不包含第二个参数,一直取到串的结束。

1
2
3
string str = "abcdefgcd";
cout<<str.substr(0,3);//abc
cout<<str.substr(3);//defgcd

string没有提供left,right函数,来从左边和右边取子串,造成了一些不便,需要采用技巧来实现。

取左串:str.substr(0, n) ;

取右串:str.substr(str.size()-n);

⑧字串比较:

比较两个字串,使用compare函数,可以比较全字串,或串中若干个字符。字符串比较是按字符的ASCII码进行对比。

= 返回 0 > 返回 1 < 返回 -1

1
2
3
4
string str = "abcdefgcd";
cout<<str.compare("abcdefgcd");//0

cout<<str.compare(0,3,"abc");//0 从str位置0开始,和"abc"比较3个字符。
⑨其它常用操作:

对于string,还有一些常用的操作。

返回字串长度的size(),例:len = str.size();

下标操作at(),例:c = str.at(1);str.at(2)= "5";

下标操作也可以用[],例:c = str[1];str[2]= "5";

四,代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include<string>
using namespace std;
int main()
{
string str;
getline(cin,str);


for(int i=0;i<str.length();i++){
if(i==0&&str[i]>='a'&&str[i]<='z') str[i]-=32;//处理首个大写字母
if(str[i]==' '){
int j=i+1;
while(str[j]==' '){//处理空格
str.erase(str.begin()+j);
}
if(str[j]>='a'&&str[j]<='z') str[j]-=32;//处理句中大写字母
}
//处理_
if((str[i]-'0')>=0&&(str[i]-'0')<=9&&((str[i+1]>='a'&&str[i+1]<='z')||(str[i+1]>='A'&&str[i+1]<='Z'))) str.insert(i+1,"_");
if((str[i]-'0')>=0&&(str[i]-'0')<=9&&((str[i-1]>='a'&&str[i-1]<='z')||(str[i-1]>='A'&&str[i-1]<='Z'))) str.insert(i,"_");
}

cout<<str<<endl;
return 0;
}