本题要求你实现一个稍微更值钱一点的 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、无论用户说什么,首先把对方说的话在一行中原样打印出来;
2、消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
3、把原文中所有大写英文字母变成小写,除了 I;
4、把原文中所有独立的 can you、could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词;
5、把原文中所有独立的 I 和 me 换成 you;
6、把原文中所有的问号 ? 换成惊叹号 !;
7、在一行中输出替换后的句子作为 AI 的回答。
其中1和7为同一类问题,3和6为同一类问题,4和5为同一类问题,2为一类问题。
此题最好使用自定义函数,代码将会变得简洁明了。理论上我们应该创建四种函数(分别对应四类问题)。c语言标准库里提供丰富的函数,里面存在我们所需的函数:
1,tolower(int tolower(int c)):把字母字符转换成小写,非字母字符不做出处理.
2,isalnum(int isalnum(int c)) :判断字符变量c是否为字母或数字,若是则返回非零,否则返回零。
3,ispunct(int ispunct(int c)):检查参数c是否为标点符号或特殊符号。(checks for any printable character which is not a space or an alphanumeric character.)
5,strstr:之前的博客(7-6 敲笨钟 (10分)(附详细讲解))已讲述。
6,memset(void *memset(void *s, int c, size_t n)):某一块内存中的内容全部设置为指定的值。n为字节数。
注意:我们需要注意题目要求是将 原文中符合要求的做替换,因我们要小心替换。所以我们先将can you、could you 对应替换成 i can、i could。这样就能防止5的替换发生错误!因为使用自定义函数调用自定义函数,因此需要将最里层的函数声明写在main函数前面!此题需要掌握有关指针的基础知识!
代码展示如下:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#define len 10000
void substitute(char a[][len],char* q,char* t1,char* r1,int i);
void dele(char a[][len],int i)
{
int j=0;
int k=0;
int count=0;
char temp[]=" ";
/*把行首的空格全部删掉*/
count=strlen(a[i]);
for(;;)
{
if(a[i][0]==32)
for(j=0;j<count;++j)
a[i][j]=a[i][j+1];
else
break;
}
/*把相邻单词间的多个空格换成 1 个空格*/
for(;;)
{
if(strstr(a[i],temp)!=NULL)
{
for(j=(strstr(a[i],temp)-a[i]);j<count;++j)
a[i][j]=a[i][j+1];
}
else
break;
}
/*把标点符号前面的空格删掉*/
j=0;
for(;j<count;++j)
if(ispunct(a[i][j+1])!=0&&a[i][j]==32)
{
for(k=j;k<count;++k)
a[i][k]=a[i][k+1];
--j;
}
/*把行尾的空格全部删掉*/
for(;;)
{
count=strlen(a[i]);
if(a[i][count-1]==32)
a[i][count-1]=0;
else
break;
}
return;
}
/*把原文中所有独立的can you could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词,把原文中所有独立的 I 和 me 换成 you*/
void replace(char a[][len],int i)
{
char t1[]="can you";
char t2[]="could you";
char r1[]="i can";
char r2[]="i could";
char t3[]="I";
char t4[]="me";
char r3[]="you";
char *q=a[i];
/*can you*/
substitute(a,a[i],t1,r1,i);
/*could you*/
substitute(a,a[i],t2,r2,i);
/*I*/
substitute(a,a[i],t3,r3,i);
/*me*/
substitute(a,a[i],t4,r3,i);
/* i变成I*/
while(strstr(a[i],r1)!=NULL)
{
q=strstr(a[i],r1);
*q='I';
}
/* i变成I*/
while(strstr(a[i],r2)!=NULL)
{
q=strstr(a[i],r2);
*q='I';
}
return;
}
/*把原文中所有大写英文字母变成小写,除了 I;把原文中所有的问号 ? 换成惊叹号 !;*/
void lower(char a[][len],int i)
{
int j=0;
/*感叹号替换*/
for(j=0;a[i][j]!=0;++j)
if(a[i][j]=='?')
a[i][j]='!';
/*变小写*/
for(j=0;a[i][j]!=0;++j)
if(a[i][j]!='I')
a[i][j]=tolower(a[i][j]);
return;
}
void substitute(char a[][len],char* q,char* t1,char* r1,int i)
{
char temp1[len]={0};
char temp2[len]={0};
int count=0;
int leap=0;
leap=strlen(t1);
for(;;)
{
if(strstr(q,t1)!=NULL)
{
q=strstr(q,t1);
if((isalnum(*(q-1))!=0&&q!=a[i])||isalnum(*(q+leap))!=0)
q=q+leap;
else
{
count=q-a[i];
strncpy(temp2,a[i],count);
strcat(temp2,r1);
strcpy(temp1,q+leap);
strcat(temp2,temp1);
strcpy(a[i],temp2);
memset(temp1,0,len);
memset(temp2,0,len);
}
}
else
break;
}
return;
}
int main(void)
{
char a[11][len]={0};
int i=0;
int n=0;
scanf("%d",&n);
getchar();
for(i=0;i<n;++i)
gets(a[i]);
for(i=0;i<n;++i)
{
printf("%s\n",a[i]);
dele(a,i);
lower(a,i);
replace(a,i);
printf("AI: %s\n",a[i]);
}
return 0;
}
总结:strstr每次只能返回第一个符合要求的位置,因此需要用指针存储此地址,因为题目要求的是把独立子字符串替换,所以我们判断strstr返回的地址是否符合我们的要求,如果不是就需要跳过查找下一个…如果符合就使用substitute函数做替换。此题处理顺序应该为删除空格、转小写、替换。因为strcat不会覆盖目的地字符串,因此我们要手动清空目的地字符串中的内容!使用memset函数即可。