去年这时候做过这道题,卡在测试点4
今天看到以前的L1题目还剩两道没做对,就想着改改试试,这道改了一晚上才过,难受,坑点太多了。。好不容易本来改到了测试点4格式错误的程度,感谢这个博客 提到的第4点,让我最后终于过了。
去年写的代码现在看真的是。。。看不懂,写的乱糟糟的,77行我都看不下去,决心重写,呜呜太难搞了,后来写的也是一团糟,不美观。
这次加上注释120多行 [头秃👴],为了纪念这次艰难的过程,上AC代码。
//(1) 无论用户说什么,首先把对方说的话在一行中原样打印出来;
//(2) 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
//(3) 把原文中所有大写英文字母变成小写,除了 I;
//(4) 把原文中所有独立的 can you、could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词;
//(5) 把原文中所有独立的 I 和 me 换成 you;
//(6) 把原文中所有的问号 ? 换成惊叹号 !;
//(7) 在一行中输出替换后的句子作为 AI 的回答。
#include <iostream>
#include <sstream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
// 记录每个分隔符后面有几个空格
// 当时没明白到底分隔符和下一个单词之间的空格要输出几个所以有了这个
int separ[2005] = {};
/**
* 判断一个字符是否是分隔符,如果不是则返回 0
* 如果是空格则返回 1,其他分隔符则返回 2
*/
int isseparator(char c)
{
if (c == ' ') return 1;
if (c >= 'a' && c <= 'z') return 0;
if (c >= 'A' && c <= 'Z') return 0;
if (c >= '0' && c <= '9') return 0;
return 2;
}
/**
* 将字符串 a 中的大写变小写(除 I 外)
* 记录下除空格外的分隔符其后有多少空格
* 再将前后各加一个空格
* 将变化后的字符串存到 t 里
* 返回分隔符的个数
*/
int lowercase(string &a, string &t)
{
t = "";
int numsep = 0; // 分隔符计数
memset(separ, 0, sizeof(separ));
for (int i = 0; a[i]; i++)
{
if (a[i] >= 'A' && a[i] <= 'Z' && a[i] != 'I')
{
t += (char)(a[i] + 32); //除"I"外,大写换小写 //(3)
}
else if (isseparator(a[i]) == 2)
{
/* 给所有不是" "空格的分隔符前后各加上一个空格 */
if (a[i] == '?') a[i] = '!'; // "?"换成"!" //(6)
t += " ";
t += a[i];
t += " ";
/* 记录下原来后面空格的个数 */
i++;
int cnt = 0;
while(isseparator(a[i])==1)
{
cnt++;
i++; // 最后多加了一次
}
separ[++numsep] = cnt;
i--; // 在这去掉
}
else t += a[i]; // 不是非空格分隔符也不是大写字母就直接挪过来
}
return numsep;
}
int main()
{
int n;
cin >> n;
string s, t;
getline(cin, s);
while (n--)
{
getline(cin, s);
cout << s << endl << "AI:"; //(1)
lowercase(s, t); // 变化后的字符串存到 t
/* 以空格为分隔,将子字符串存入 vs */ //(2)
vector<string> vs;
stringstream ss(t);
while (ss>>s)
{
vs.push_back(s);
}
/* 输出过程 */
int cnt = 0, flag = 0; // cnt 分隔符计数, flag 分隔符标记
for (size_t i = 0; i < vs.size(); i++)
{
if (isseparator(vs[i][0]) == 2) //如果是个分隔符
{
/* 如果在开头上要加空格,否则不加空格 */ //(2)
if (i == 0) cout << " ";
cout << vs[i];
cnt++; //第几个分隔符
flag = 1; //标记上
}
else // 不是分隔符
{
/* 是否输出空格 */
if (flag) //前一个是分隔符
{
// 如果上一个分隔符后有空格则输出一个空格
if (separ[cnt]) cout << " "; //(2)
flag = 0; //标记恢复0
}
else cout << " "; //前一个不是分隔符输出空格 //(2)
/* 变化还是直接输出 */
if (vs[i] == "I" || vs[i] == "me")
{
cout << "you"; //(5)
}
else if ((vs[i] == "can" || vs[i] == "could") && i < vs.size()-1 && vs[i+1] == "you")
{
cout << "I " << vs[i]; //(4)
i++;
}
else cout << vs[i]; //直接输出
}
}
/* 如果输入一行空格则输出空格和换行 */ /***坑点***/
if (vs.size() == 0) cout << " ";
cout << endl;
}
return 0;
}