PAT (Basic Level) Practice 1033 旧键盘打字 (20分) (string中的判断函数、find函数、erase函数)

1.题目

旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及坏掉的那些键,打出的结果文字会是怎样?

输入格式:

输入在 2 行中分别给出坏掉的那些键、以及应该输入的文字。其中对应英文字母的坏键以大写给出;每段文字是不超过 10​5​​ 个字符的串。可用的字符包括字母 [a-zA-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;
}

posted @ 2020-02-22 21:54  Jason66661010  阅读(134)  评论(0编辑  收藏  举报