以上图片来自新浪微博。
本题要求你实现一个稍微更值钱一点的 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
这题有两个坑点:
1、can you,could you, I, me的替换是在将字母转换成小写字母后进行的,如果原文中有 ME ,最后也是会被替换成you的。
2、can you,could you,I,me 的替换是独立的,假设原文中含有 can you,我们将其替换成I can,那么我们就不能再接着把I替换成 you,得到you can,这是错误的。
最近刚学了正则表达式,发现用来解这题真的非常合适,代码只有二十多行,有兴趣可以了解一下。贴个代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
getchar();
while(n--)
{
string str;
getline(cin,str);
cout<<str<<endl;
str=regex_replace(str,regex(" +")," ");
str=regex_replace(str,regex(" ([^\\w ])"),"$1");
while(str[0]==' ') str.erase(str.begin());
while(str.back()==' ') str.pop_back();
for(int i=0;i<str.size();i++)
if(str[i]>='A'&&str[i]<='Z'&&str[i]!='I')
str[i]+=' ';
//本来是要替换成I can的,但是为了防止下一步继续将I变成you
//先替换成% can,后续再把%替换成I
str=regex_replace(str,regex("\\bcan you\\b"),"% can");
str=regex_replace(str,regex("\\bcould you\\b"),"% could");
str=regex_replace(str,regex("\\b(I|(me))\\b"),"you");
for(int i=0;i<str.size();i++)
if(str[i]=='?') str[i]='!';
else if(str[i]=='%') str[i]='I';
cout<<"AI: "<<str<<endl;
}
return 0;
}
不会正则表达式也没关系,理清思路就行,代码也不算长,五十行左右
我们先做这几个操作
- 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
- 把原文中所有大写英文字母变成小写,除了
I
; - 把原文中所有的问号
?
换成惊叹号!
;
再做替换操作
在替换的时候是针对做完上述操作后的字符串原文进行替换的,具体看代码
- 把原文中所有独立的
can you
、could you
对应地换成I can
、I could
—— 这里“独立”是指被空格或标点符号分隔开的单词; - 把原文中所有独立的
I
和me
换成you
;
#include<bits/stdc++.h>
using namespace std;
//check 函数用来判断是否独立。
bool check(string& temp,int l,int r)
{
if((l<0||!isalnum(temp[l]))&&(r>=temp.size()||!isalnum(temp[r])))
return true;
return false;
}
int main()
{
int n;
cin>>n;
getchar();
while(n--)
{
string str;
getline(cin,str);
cout<<str<<endl;
//第一大步操作
string temp;
for(int i=0;i<str.size();i++)
if(str[i]==' ')
{
//消除多余空格,消除符号前的空格
if(!temp.size()) continue;
while(i<str.size()&&str[i]==' ') i++;
if(i==str.size()) break;
if(isalnum(str[i])) temp+=' ';
i--;
}else
{
if(str[i]>='A'&&str[i]<='Z'&&str[i]!='I')
temp+=str[i]+' '; //大写转小写
else if(str[i]=='?') temp+='!'; //问号改为感叹号
else temp+=str[i]; //其他字符不需要变
}
//进行第二大步操作
//我们在这里只看原文,把答案都放进res中,就不用考虑can you变成I can后I再次被替换的情况了。
string res;
for(int i=0;i<temp.size();i++)
if(temp[i]=='I'&&check(temp,i-1,i+1))
res+="you";
else if(i+1<temp.size()&&temp.substr(i,2)=="me"&&check(temp,i-1,i+2))
res+="you",i++;
else if(i+6<temp.size()&&temp.substr(i,7)=="can you"&&check(temp,i-1,i+7))
res+="I can",i+=6;
else if(i+8<temp.size()&&temp.substr(i,9)=="could you"&&check(temp,i-1,i+9))
res+="I could",i+=8;
else res+=temp[i];
cout<<"AI: "<<res<<endl;
}
return 0;
}
这题挺锻炼对字符串处理的能力的。