以上图片来自新浪微博。
本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是:
无论用户说什么,首先把对方说的话在一行中原样打印出来;
消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
把原文中所有大写英文字母变成小写,除了 I;
把原文中所有独立的 can you、could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词;
把原文中所有独立的 I 和 me 换成 you;
把原文中所有的问号 ? 换成惊叹号 !;
在一行中输出替换后的句子作为 AI 的回答。
输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。
按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。
6
Hello ?
Good to chat with you
can you speak Chinese?
Really?
Could you show me 5
What Is this prime? I,don 't know
Hello ?
AI: hello!
Good to chat with you
AI: good to chat with you
can you speak Chinese?
AI: I can speak chinese!
Really?
AI: really!
Could you show me 5
AI: I could show you 5
What Is this prime? I,don 't know
AI: what Is this prime! you,don't know
封装的函数比较多,写的代码也很长,不过应该更好理解。
测试点0占10分,应该是字母转小写的问题,一开始我整道题只得了1分(写了那么久还只是1分崩溃了...),后面我才发现我理解错了”把原文中所有大写英文字母变成小写,除了 I“这句话。意思是句子中本来是大写的"I"就不需要转小写了,比如样例6中的二个单词是"Is",并不需要转成"is",我还以为只有独立的I需要大写...改过来后就15分了。
不确定自己的独立是否实现可以试试:输入“can youI”正确输出为"can youI"、输入“meI”正确输出为"meI"、输入“II”正确输出为"II"。
测试点4应该是题目要求4和要求5的先后顺序的问题,我是通过先完成要求5,再完成要求4解决的。
比如输入"can me”,如果先实现要求5,变为"can you",再实现要求4会变成"I can",但是这样是错的,正确的输出是"can you"。
#include
#include
using namespace std;
//把原文中所有大写英文字母变成小写,除了 I
void letterLower(string& str)
{
for (int i = 0; i < str.size(); i++)
{
if (str[i] >= 'A' && str[i] <= 'Z' && str[i] != 'I')
{
str[i] += 32;
}
}
}
//消除多余空格
void delSpace(string& str)
{
//把行首的空格全部删掉
while (str.front() == ' ')
{
str.erase(0, 1);
if (str.size() == 0)
return;
}
//把行尾的空格全部删掉
while (str.back() == ' ')
{
str.pop_back();
}
//把相邻单词间的多个空格换成 1 个空格
int pos = 0;
while (pos < str.size() - 1)
{
if (str[pos] == ' ' && str[pos + 1] == ' ')
{
str.erase(pos, 1);
continue;
}
pos++;
}
//把标点符号前面的空格删掉
for (int i = 0; i < str.size() - 1; i++)
{
if (str[i] == ' ')
{
//除了大写I、小写字母、数字以外的都是标点符号
if (str[i + 1] == 'I'|| (str[i + 1] >= 'a' && str[i + 1] <= 'z')|| (str[i + 1] >= '0' && str[i + 1] <= '9'))
continue;//如果不是标点符号,就不删除
str.erase(i, 1);
}
}
}
//把原文中所有的问号 ? 换成惊叹号 !
void changeQues(string& str)
{
for (int i = 0; i < str.size(); i++)
{
if (str[i] == '?')
str[i] = '!';
}
}
//把原文中所有独立的 can you、could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词
void answer(string& str)
{
int pos = 0;//从头开始处理can you
while (pos < str.size())
{
int findpos = str.find("can you", pos);
if (findpos == -1)//如果找不到就结束循环
break;
if (findpos == 0)//如果can you在句子开头
{
if (str.size() == 7)//如果句子只是can you,为了防止越界,应该结束循环
{
str.replace(findpos, 7, "I can");
break;
}
else if (!(str[findpos + 7] >= 'a' && str[findpos + 7] <= 'z') && !(str[findpos + 7] >= '0' && str[findpos + 7] <= '9') && str[findpos + 7] != 'I' && str[findpos + 7] != 'B')
{
str.replace(findpos, 7, "I can");
}
pos++;
continue;
}
//"can you"出现在最后
if (findpos + 7 == str.size() && !(str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z') && !(str[findpos - 1] >= '0' && str[findpos - 1] <= '9') && str[findpos - 1] != 'I' && str[findpos - 1] != 'B')
{
str.replace(findpos, 7, "I can");
break;//防止下面代码的越界访问
}
if ((str[findpos + 7] >= 'a' && str[findpos + 7] <= 'z') || (str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z'))//如果can you前后是小写字母
{
pos++;//继续从后一位找
continue;
}
if ((str[findpos + 7] >= '0' && str[findpos + 7] <= '9') || (str[findpos - 1] >= '0' && str[findpos - 1] <= '9'))//如果can you前面或后面是数字
{
pos++;//继续从后一位找
continue;
}
if ((str[findpos + 7] == 'I') || (str[findpos - 1] == 'I'))//如果can you前后是大写I
{
pos++;//继续从后一位找
continue;
}
if (str[findpos + 7] == 'B')//如果you后是标记用的大写字母B
{
pos++;//继续从后一位找
continue;
}
//如果都不是,说明是独立的can you
str.replace(findpos, 7, "I can");
pos++;
}
pos = 0;//从第一位开始处理could you
while (pos < str.size())
{
int findpos = str.find("could you", pos);
if (findpos == -1)//如果找不到
break;
if (findpos == 0)//如果could you在句子开头
{
if (str.size() == 9)//如果句子只是could you,为了防止越界,应该结束循环
{
str.replace(findpos, 9, "I could");
break;
}
else if (!(str[findpos + 9] >= 'a' && str[findpos + 9] <= 'z') && !(str[findpos + 9] >= '0' && str[findpos + 9] <= '9') && str[findpos + 9] != 'I' && str[findpos + 9] != 'B')
{
str.replace(findpos, 9, "I could");
}
pos++;
continue;
}
if (findpos + 9 == str.size() && !(str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z') && !(str[findpos - 1] >= '0' && str[findpos - 1] <= '9') && str[findpos - 1] != 'I' && str[findpos + 9] != 'B')//"could you"出现在最后
{
str.replace(findpos, 9, "I could");
break;
}
if ((str[findpos + 9] >= 'a' && str[findpos + 9] <= 'z') || (str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z'))//如果could you前面或后面是小写字母
{
pos++;//继续从后一位找
continue;
}
if ((str[findpos + 9] >= '0' && str[findpos + 9] <= '9') || (str[findpos - 1] >= '0' && str[findpos - 1] <= '9'))//如果could you前面或后面是数字
{
pos++;//继续从后一位找
continue;
}
if ((str[findpos + 9] == 'I') || (str[findpos - 1] == 'I'))//如果could you前后是大写I
{
pos++;//继续从后一位找
continue;
}
if (str[findpos + 9] == 'B') //you不能标记后的youB
{
pos++;//继续从后一位找
continue;
}
//如果都不是,说明是独立的could you
str.replace(findpos, 9, "I could");
pos++;
}
}
//把原文中所有独立的 I 和 me 换成 you
//在这暂时先换成youB,方便和can you,could you的you区分开来
void changePerson(string& str)//切换人称
{
int pos = 0;//从头开始处理独立的me
while (pos < str.size())
{
int findpos = str.find("me", pos);
if (findpos == -1)//如果找不到
break;
if (findpos == 0)//防止越界,单独处理
{
if (str.size() == 2)//句子只是me
{
str.replace(findpos, 2, "youB");
break;
}
else if(!(str[findpos + 2] >= 'a' && str[findpos + 2] <= 'z') && !(str[findpos + 2] >= '0' && str[findpos + 2] <= '9') && str[findpos + 2] != 'I')
str.replace(findpos, 2, "youB");
pos++;
continue;
}
if (findpos + 2 == str.size() && !(str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z') && !(str[findpos - 1] >= '0' && str[findpos - 1] <= '9') && str[findpos - 1] != 'I')//"me"出现在最后
{
str.replace(findpos, 2, "youB");
break;
}
if ((str[findpos + 2] >= 'a' && str[findpos + 2] <= 'z') || (str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z'))//如果me前面或后面是小写字母
{
pos++;//继续从后一位找
continue;
}
if ((str[findpos + 2] >= '0' && str[findpos + 2] <= '9') || (str[findpos - 1] >= '0' && str[findpos - 1] <= '9'))//如果me前面或后面是数字
{
pos++;//继续从后一位找
continue;
}
if ((str[findpos + 2] == 'I') || (str[findpos - 1] == 'I'))//如果me前后是大写I
{
pos++;//继续从后一位找
continue;
}
//如果都不是,说明是独立的me
str.replace(findpos, 2, "youB");
pos++;
}
pos = 0;//从头开始处理独立的I
while (pos < str.size())
{
int findpos = str.find("I", pos);
if (findpos == -1)
break;
if (findpos == 0)//防止越界,单独处理
{
if (str.size() == 1)//句子只是I
{
str.replace(findpos, 1, "youB");
break;
}
else if (!(str[findpos + 1] >= 'a' && str[findpos + 1] <= 'z') && !(str[findpos + 1] >= '0' && str[findpos + 1] <= '9') && str[findpos + 1] != 'I')
str.replace(findpos, 1, "youB");
pos++;
continue;
}
if (findpos + 1 == str.size() && !(str[findpos - 1] >= '0' && str[findpos - 1] <= '9') && !(str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z') && str[findpos - 1] != 'I')
{
str.replace(findpos, 1, "youB");
break;
}
if ((str[findpos - 1] >= '0' && str[findpos - 1] <= '9') || (str[findpos + 1] >= '0' && str[findpos + 1] <= '9'))
{
pos++;
continue;
}
if ((str[findpos - 1] >= 'a' && str[findpos - 1] <= 'z') || (str[findpos + 1] >= 'a' && str[findpos + 1] <= 'z'))
{
pos++;
continue;
}
if (str[findpos - 1] == 'I' || (str[findpos + 1] == 'I'))
{
pos++;
continue;
}
//代码走到这还没continue,说明独立
str.replace(findpos, 1, "youB");
pos++;
}
}
void eraseB(string& str)
{
for (int i = 0; i < str.size(); i++)
{
if (str[i] == 'B')
str.erase(i, 1);
}
}
void AI(string& str)
{
cout << "AI: ";
changeQues(str);
letterLower(str);
delSpace(str);
changePerson(str);
answer(str);
eraseB(str);//将标记用的B删除
}
int main()
{
int n; cin >> n;
getchar();
while (n--)
{
string str;
getline(cin, str);
cout << str << endl;
AI(str);
cout << str << endl;
}
return 0;
}
真的写的好长,这题我也写了很久(一整个晚上),在大学里写没写出来,现在放寒假了从头开始写过...
水平不高,如有不正确的地方,欢迎大家在评论区指正^_^