PAT (Basic Level) Practice 1033 旧键盘打字 (20分) (string中的判断函数、find函数、erase函数)
1.题目
旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及坏掉的那些键,打出的结果文字会是怎样?
输入格式:
输入在 2 行中分别给出坏掉的那些键、以及应该输入的文字。其中对应英文字母的坏键以大写给出;每段文字是不超过 105 个字符的串。可用的字符包括字母 [a
-z
, A
-Z
]、数字 0
-9
、以及下划线 _
(代表空格)、,
、.
、-
、+
(代表上档键)。题目保证第 2 行输入的文字串非空。
注意:如果上档键坏掉了,那么大写的英文字母无法被打出。
输出格式:
在一行中输出能够被打出的结果文字。如果没有一个字符能被打出,则输出空行。
输入样例:
7+IE.
7_This_is_a_test.
输出样例:
_hs_s_a_tst
2.题目分析
1.这种题目思路就是遍历较为长的字符串,在短的字符串中做判断,这样方便也较为节省时间,开始我并没有这样做,导致思路臃肿,代码繁杂
2.开始的思路就是遍历短的字符串,如果长字符串中有该字符就将其使用erase函数删掉(细节处理在代码中有注释)
3.之后的思路就是直接遍历长的字符串,如果该字符在短的字符串中存在,就不输出直接跳过,无需使用erase函数删除
4.坑点:+上档键就是shift键,出现+表示A~Z都坏了(原谅我不知道上档键是啥……)
还有就是可能没有坏键,第一个字符串为空
要删除的字符可能重复(方法一)
3.知识分析
参考(https://www.cnblogs.com/mini-coconut/p/8977796.html)
isdigit( ) 检测字符串是否只由数字组成
islower( ) 检测字符串是否由小写字母组组成
isupper( ) 检测字符串中所有的字母是否都为大写
isalpha( ) 检测字符串是否只由字母组成
isspace( ) 检测字符串是否只由空格组成
toupper()从小写变为大写
tolower()从大写变为小写
find函数:
find()查找字符、字符串,为空返回string::npos
rfind() 是从指定位置起向前查找,直到串首 eg:list.rfind('a',6);
find_first_of() 只要在源串中遇到一个字符,该字符与目标串中任意一个字符相同,就停止查找,返回该字符在源串中的位置
例如:
string str1("bcgjhikl"); string str2("kghlj"); cout << str1.find_first_of(str2, 0) << endl; //从str1的第0个字符b开始找,b不与str2中的任意字符匹配;再找c,c不与str2中的任意字符匹配;再找g, //g与str2中的g匹配,于是停止查找,返回g在str1中的位置2
find_last_of() 从后向前找
find_first_not_of()在源串中从位置pos开始往后查找,只要在源串遇到一个字符,该字符与目标串中的任意一个字符都不相同,就停止查找,返回该字符在源串中的位置;
string str("abcdefg"); cout << str.find_first_not_of("kiajbvehfgmlc", 0) << endl;//3 // 从源串str的位置0(a)开始查找,目标串中有a(匹配),再找b,b匹配,再找c,c匹配, // 再找d,目标串中没有d(不匹配),停止查找,返回d在str中的位置3
find_last_not_of()从后向前
erase函数:参考(https://www.cnblogs.com/ylwn817/articles/1967689.html)
(1)erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符 (2)erase(position);删除position处的一个字符(position是个string类型的迭代器) (3)erase(first,last);删除从first到last之间的字符(first和last都是迭代器)
int main () { string str ("This is an example phrase."); string::iterator it; // 第(1)种用法 str.erase (10,8);//删除位置10后面的8个字符 cout << str << endl; // "This is an phrase." // 第(2)种用法 it=str.begin()+9; str.erase (it);//删除一个字符 cout << str << endl; // "This is a phrase." // 第(3)种用法 str.erase (str.begin()+5, str.end()-7);//删除一段字符 cout << str << endl; // "This phrase." return 0; }
4.代码
开始的代码:
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
string a;
string list;
getline(cin, a);//这里不能使用cin,因为可能键盘一个未错,a为空只有回车,cin自动过滤导致程序出错,但是getline不会过滤回车,a为空程序继续执行
getline(cin, list);
if (a.find('+') != string::npos)//这里出现+,表示A~Z都坏了
{
for (int i = 0; i <= 26; i++)
{
for (int j = 0; j < list.length(); j++)//原来这里使用while(list.find('A'+i)!=string::npos)list.erase(list.find('A'+i),1);
{ //使用while是因为后面可能还有同样的字符未删除,必须直到找不见才是删除干净,但是这样最后一个测试点超时
if (list[j] == ('A' + i))
{
list.erase(j, 1); j--;//于是使用遍历查找,又想到如果找到一次erase后,字符串长度就会变,所以删除一个后就将j--;保证每个字符都检验一遍
}
}
}
}
for (int i = 0; i<a.length(); i++)
{
if (a[i] >= 'A'&&a[i] <= 'Z')//出现大写字符,将大小写全部检测
{
for (int j = 0; j < list.length(); j++)if (list[j] == a[i]) { list.erase(j, 1); j--; }
for (int j = 0; j < list.length(); j++)if (list[j] == (a[i] + 32)) { list.erase(j, 1); j--; }
}
else
{
for (int j = 0; j < list.length(); j++)if (list[j] == a[i]) { list.erase(j, 1); j--; }
}
}
cout << list << endl;
}
改进的代码:
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
string a;
string list;
getline(cin, a);
getline(cin, list);
/*cin >> a;
cin>>list;*/
for (int i = 0; i < list.length(); i++)
{
if (islower(list[i]) && a.find(toupper(list[i])) != string::npos)continue;//如果是小写字符并且对应的大写字符在坏键字符串中,就不必输出
else if (isupper(list[i]) && (a.find(list[i]) != string::npos || a.find('+') != string::npos))continue;//如果是大写字符,在坏键字符串中或者是有+,不必输出
else if (a.find(list[i]) != string::npos)continue;//在坏键字符串中,不输出
cout << list[i];
}
cout << endl;
}