标签:边界问题 分割 第一个字符 sed strong 老师 dde play pen
7-2 AI核心代码 (30 分)
本题要求你实现一个简易版的 AI 英文问答程序,规则是:
这道题是上机课上老师带着做到,看到这道题时,首先想到的时用if else或者case,但是看了一下要实现的内容,有太多的边界问题了。
根据题目所给的规则,可以把处理的问题分为:空格、大写变小写(除了I)、独立的I和me改为you、?变!、独立的can you变为I can。
按照老师的思路,首先从主函数开始写起,主函数主要是实现输入的功能。
int main() { int n; string s; cin>>n; getchar(); //吸收回车 for(int i=1;i<=n;i++) {//输入对话 getline(cin,s); cout<<s<<endl; cout<<"AI: "; go(s); //根据s输出AI的回答 } return 0; }
根据main函数中构造调用的一个go函数,可以开始构思如何写go函数,其中go函数的功能主要是根据输入的内容,输出相应的内容。
下面开始写go函数:
一开始是定义string t,我们有选择地把我们需要输出的字符放到数组t中,到最后直接输出t数组的元素即可。但是这会出现问题,因为我们给t分配了空间,但是我们并不知道这个空间的首地址。所以改为定义一个字符数组t,根据题目,每一句不超过字符1000,那我们设的长度是不是1000或者1001就足够了呢?不是的,如果输入的字符全为I,那么长度为1000或1001显然是不够的,因此设定的长度应为3001。在处理前面根据规则分的五类的问题前,我们要先用一个空循环定位到字符串s的第一个非空元素,因为一句话最前面的空格我们是不需要输出的。
char t[3001]; //输入全为I时,输出的长度是输入的3倍 int i,j=0; //i为s的下标,j为t的下标 for(i=0;s[i]!=‘\0‘&&s[i]==‘ ‘;i++); //定位到s的第一个非空(循环体为空)
定位到s的第一个非空元素后,我们先处理s中的空格的问题:在一句话中间有连续的空格
方法:连续空格的一个特点是,当前扫描字符是空格,前一个也是空格,这时,除了第一个空格可以放进数组t以外,其他空格都不需要放进数组t里。
if(s[i]==‘ ‘&&s[i-1]==‘ ‘) {//连续空格时,只copy一个空格 i++; continue; }
解决?→!的问题
方法:当前扫描字符为?时,放进数组t的字符为!。
if(s[i]==‘?‘) //解决?->! { t[j++]=‘!‘; i++; continue; }
解决大写转小写的问题(除了I)
方法,先判断当前元素是否为I,如果是,则放进数组t,如果不是,则先转换成小写,再放进数组t里
if(s[i]!=‘I‘) {//如果当前的元素不是I就大小写并转换 t[j]=tolower(s[i]); //大写转小写 i++; j++; continue; } else t[j++]=s[i++]; //当s[i]=I时,直接写入t数组
处理完字符串s后,此时的数组t已经是处理完连续空格、?→!、大写转小写的字符串s了,这时应该在数组t的后面加个结尾符。
此时的数组t是否就是我们想要的最后结果呢?当然不是,空格问题我们只处理了连续空格还有开头空格的问题,还有分割符前的空格以及每句话最后的空格我们还没有处理。
处理分隔符前空格的方法:判断条件是:当前扫描字符为空格,且下一个扫描的字符为分割符。
处理每句话最后的空格的方法:判断条件:当前扫描字符为空格,且下一个扫描的字符为结尾符。
if(t[j]==‘ ‘ && inDependent(t[j+1])) {//分隔符前没有空格 j++; continue; } if(s[j]==‘ ‘&&s[j+1]==‘\0‘) {//处理最后一个空格 j++; continue; }
在处理剩余空格问题时,用到了一个判断是否为分隔符的函数
bool inDependent(char ch) {//判断ch是否为分隔字符 ch=tolower(ch); //把大写转换成小写,便于比较 if(ch>= ‘0‘ && ch<=‘9‘ || ch>=‘a‘ && ch<=‘z‘) return false; else return true; }
处理完剩余的空格问题后,开始处理独立的I和me转换成you
I转换成you的方法:判断条件:当前扫描字符为I,同时前一个字符以及后一个字符为分隔符。但是这时有可能会发生越界,当字符的第一个就是I时,此时j-1就成了-1,发生了越界。因此在判断I的前一个字符是否为分隔符时,首先判断I是否为第一个字符。而I的下一个字符处不用担心越界问题,因为就算I是最后一个字符,在I的后面还有一个结尾符,因此不会发生越界。
me转换成you的方法:判断条件:当前扫描字符为m,以及下一个扫描字符为e,同时前一个字符以及后一个字符为分隔符。me和上面I的情况一样,有可能会发生越界问题。要做相同的处理
if(t[j]==‘I‘ && (j==0 || inDependent(t[j-1])) && inDependent(t[j+1])) //独立的I转成you {//把独立的I转换成you,要考虑I就是第一个字符的情况,j=0处有可能发生越界 cout<<"you" ; j++; continue; } if(t[j]==‘m‘ && t[j+1]==‘e‘ && (j==0 || inDependent(t[j-1])) && inDependent(t[j+2])) //独立的me转成you {//把独立的me转换成you,同样要考虑y是第一个字符的情况,j=0有可能发生越界 cout<<"you"; j=j+2; //右移两个字符,判断了m、e两个字符 continue; } if(t[j]==‘ ‘ && inDependent(t[j+1]))
此时只剩下独立的can you转换成I can的问题了。
方法:先判断是否为can you,再判断是否独立,同样要考虑越界的问题。
if(iscanyou(t,j)&&(j==0||inDependent(t[j-1]))&&inDependent(t[j+7])) {//把can you →I can cout<<"I can"; j=j+7; //can you一共有七个字符 continue; }
在判断是否为can you时用到了一个iscanyou的函数。
bool iscanyou(char t[],int j) {//判断是否为can you if(t[j]==‘c‘&&t[j+1]==‘a‘&&t[j+2]==‘n‘&&t[j+3]==‘ ‘&&t[j+4]==‘y‘&&t[j+5]==‘o‘&&t[j+6]==‘u‘) return true; else return false; }
全部代码如下:
#include <iostream> #include <string> #include <cstdio> using namespace std; bool inDependent(char ch) {//判断ch是否为分隔字符 ch=tolower(ch); //把大写转换成小写,便于比较 if(ch>= ‘0‘ && ch<=‘9‘ || ch>=‘a‘ && ch<=‘z‘) return false; else return true; } bool iscanyou(char t[],int j) {//判断是否为can you if(t[j]==‘c‘&&t[j+1]==‘a‘&&t[j+2]==‘n‘&&t[j+3]==‘ ‘&&t[j+4]==‘y‘&&t[j+5]==‘o‘&&t[j+6]==‘u‘) return true; else return false; } void go(string s) {//根据s输出AI的回答 char t[3001]; //输入全为I时,输出的长度是输入的3倍 int i,j=0; //i为s的下标,j为t的下标 for(i=0;s[i]!=‘\0‘&&s[i]==‘ ‘;i++); //定位到s的第一个非空(循环体为空) while(s[i]!=‘\0‘) //把s串copy到t { if(s[i]==‘ ‘&&s[i-1]==‘ ‘) //连续空格时,只copy一个空格 { i++; continue; } if(s[i]==‘?‘) //解决?->! { t[j++]=‘!‘; i++; continue; } if(s[i]!=‘I‘) {//如果当前的元素不是I就大小写并转换 t[j]=tolower(s[i]); //大写转小写 i++; j++; continue; } else t[j++]=s[i++]; //当s[i]=I时,直接写入t数组 } //while t[j]=‘\0‘; //给t数组补上结尾符 j=0; while(t[j]!=‘\0‘) { if(t[j]==‘I‘ && (j==0 || inDependent(t[j-1])) && inDependent(t[j+1])) //独立的I转成you {//把独立的I转换成you,要考虑I就是第一个字符的情况,j=0处有可能发生越界 cout<<"you" ; j++; continue; } if(t[j]==‘m‘ && t[j+1]==‘e‘ && (j==0 || inDependent(t[j-1])) && inDependent(t[j+2])) //独立的me转成you {//把独立的me转换成you,同样要考虑y是第一个字符的情况,j=0有可能发生越界 cout<<"you"; j=j+2; //右移两个字符,判断了m、e两个字符 continue; } if(t[j]==‘ ‘ && inDependent(t[j+1])) {//分隔符前没有空格 j++; continue; } if(iscanyou(t,j)&&(j==0||inDependent(t[j-1]))&&inDependent(t[j+7])) {//把can you →I can cout<<"I can"; j=j+7; //can you一共有七个字符 continue; } if(s[j]==‘ ‘&&s[j+1]==‘\0‘) {//处理最后一个空格 j++; continue; } cout<<t[j]; //输出 ++j; }//while cout<<endl; } int main() { int n; string s; cin>>n; getchar(); //吸收回车 for(int i=1;i<=n;i++) {//输入对话 getline(cin,s); cout<<s<<endl; cout<<"AI: "; go(s); //根据s输出AI的回答 } return 0; }
刚开始看到这道题时,觉得很难,无从下手。老师带着我们从主函数写起,再返回去写主函数中调用的函数,同时还把规则中要处理的问题分成具体的五类问题,五类问题又细分了,这样一个问题一个问题地解决就好解决了。
上次目标是做题速度快一点,这一次可能是题目简单?确实比上一次快了。再接再厉!
接下来的目标:解决问题先从主函数开始想。
标签:边界问题 分割 第一个字符 sed strong 老师 dde play pen
原文地址:https://www.cnblogs.com/ChrisMua/p/10705201.html