L1-064 估值一亿的AI核心代码(C++)

L1-064 估值一亿的AI核心代码(C++)_第1张图片

以上图片来自新浪微博。

本题要求你实现一个稍微更值钱一点的 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
L1-064 估值一亿的AI核心代码(C++)_第2张图片

封装的函数比较多,写的代码也很长,不过应该更好理解。

测试点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;
}

真的写的好长,这题我也写了很久(一整个晚上),在大学里写没写出来,现在放寒假了从头开始写过...

水平不高,如有不正确的地方,欢迎大家在评论区指正^_^

你可能感兴趣的:(c++)