L1-064 估值一亿的AI核心代码

PTA原题链接

  • 题目描述

(图略)

以上图片来自新浪微博。

本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是:

  1. 无论用户说什么,首先把对方说的话在一行中原样打印出来;
  2. 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
  3. 把原文中所有大写英文字母变成小写,除了 I;
  4. 把原文中所有独立的 can you、could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词;
  5. 把原文中所有独立的 I 和 me 换成 you;
  6. 把原文中所有的问号 ? 换成惊叹号 !;
  7. 在一行中输出替换后的句子作为 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
  • 第二次的代码

虽然不知道第一次写的那是啥玩意,但是这次的似乎更清晰些。

总体就是一步一步实现所有的功能,最后输出。题中的第3和第6条直接遍历即可,不用太担心;第2条只需要将字符串转为 stringstream 然后逐一读入,逐个添加空格(如果以标点开头则不用加)。对于第4和第5条,由于和格式的关联很大,需要将字符串先预处理。

关于预处理,因为我们需要寻找的字符串可能和标点相连,而所有标点之前的空格会在后面的输出中统一删除,所以可以先在所有标点前添加空格。但是不能在标点后添加空格,因为这样添加的空格和原有的空格会混杂而无法区分。 ans 即预处理的结果。

预处理后就可以通过 stringstream 把整个行重新读取到一个 string 数组中,在这里就是 words 。关于 getlastw()getfirstw() ,只是考虑到可能出现单词前有一个标点的情况,为方面而写的。之后的处理加就无需赘述了。

/*
 *lang C++(g++)
 *user 八衛門狸
*/
#include <algorithm>
#include <iostream>
#include <sstream>
#include <map>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long ll;

string getlastw (string n)
{
    for (int i = 0; i < n.length(); i++)
        if (isalpha(n[i])) return n.substr(i, n.length()-i);

    return "";
}

string getfirstw (string n)
{
    for (int i = 0; i < n.length(); i++)
        if (isalpha(n[i])) return n.substr(0, i);
    return "";
}

int main()
{
    string line;
    int n;
    int lenw;
    string words[10000];

    scanf("%d", &n);
    getchar();

    while (n--) {
        getline(cin, line);
        cout << line << endl << "AI: ";

        string ans = "";
        line = ' ' + line + ' ';

        // upper to lower & '?'->'!'
        for (int i = 0; i < line.length(); i++) {
            if (isupper(line[i])) {
                if (line[i] == 'I') ;
                else line[i] = tolower(line[i]);
            } else if (line[i] == '?') line[i] = '!';
        }

        // 预处理
        for (int i = 0; i < line.length(); i++) {
            if (!isalpha(line[i]) && !isdigit(line[i]) && !isspace(line[i]))
                ans = ans + " " + line[i];
            else ans += line[i];
        }

        stringstream ss(ans);
        lenw = 0;
        while (ss >> words[lenw++]) ;
        lenw--;

        for (int i = 0; i < lenw; i++) {
            if (i < lenw-1 && getlastw(words[i])=="can" && words[i+1] == "you") {
                if (words[i] == "can") {
                    words[i] = "I";
                    words[i+1] = "can";
                } else {
                    words[i] = getfirstw(words[i]) + "I";
                    words[i+1] = "can";
                }
            } else if(i < lenw-1 && getlastw(words[i])=="could" && words[i+1] == "you") {
                if (words[i] == "could") {
                    words[i] = "I";
                    words[i+1] = "could";
                } else {
                    words[i] = getfirstw(words[i]) + "I";
                    words[i+1] = "could";
                }
            } else if (getlastw(words[i])=="I") {
                if (words[i] == "I") words[i] = "you";
                else words[i] = getfirstw(words[i]) + "you";
            } else if (getlastw(words[i])=="me") {
                if (words[i] == "me") words[i] = "you";
                else words[i] = getfirstw(words[i]) + "you";
            }
        }

        int flag = 0;
        for (int i = 0; i < lenw; i++) {
            if (flag && (isalpha(words[i][0]) || isdigit(words[i][0]))) putchar(' ');
            else flag = 1;

            cout << words[i];
        }
        cout <<endl;
    }


    return 0;
}

--------------------分割线--------------------

  • 分析

实际上只是个字符串替换,显然可以用 C++ 的 regex 库解决,但是我们这里没有这么做。

  1. 观察题目的要求,显然 3 和 6 是可以一起做的;
  2. 对于 2,我们需要除去多余的空格,其实可以所有单词逐个取出,再判断何时添加单个空格。它的好处在于不用关心首尾多余的空格,也不用担心空行的出现;
  3. 先 5 后 4,否则 can you 会被替换成 you can 而不是 I can
  4. 对于 4 要注意 can you,can you ,由于我们把所有单词逐个取出,所以会被分割为 can you,can you 。为了判断方便,我们在处理大小写的时候可以在标点符号前添加空格(即使多余了空格也会在后面的操作中解决),使其可以被分割为 can you ,can you ,从而保证被逐个正确替换;
  5. 最后只要注意防断错误和一些小细节就可以了,代码中的强制类型转换是必要的。
  • AC 代码
/*
 *lang C++(g++)
 *user 八衛門狸
*/
#include <iostream>
#include <algorithm>
#include <string>
#include <cctype>
#include <cstdlib>
#include <sstream>

using namespace std;

int main()
{
        string comm;
        int no;
        scanf("%d", &no);
        getchar();

        for (int i = 0; i < no; i++) {
                getline(cin, comm);
                cout << comm << endl;
                //转小写,? -> !,每个标点前加一个空格
                for (int i = 0; i < comm.length(); i++) {
                        if (comm[i] == '?') comm[i] = '!';
                        else if (isupper(comm[i]) && comm[i] != 'I') comm[i] = tolower(comm[i]);
                        if (!isalpha(comm[i]) && !isdigit(comm[i]) && !isspace(comm[i])) {
                                comm = comm.substr(0, i) + ' ' + comm.substr(i);
                                i++;
                        }

                }

                stringstream ss(comm);
                int f = 0;
                int endline = 1;
                cout << "AI: ";
                //由于需要 4 同时判断前后两个单词,故引入 pword 作为当前单词, word 为下一单词
                string pword, word;
                ss >> pword;
                while (1) {
                        //防止最后一个单词不输出
                        if (ss >> word) ;
                        else {
                                if (endline) endline = 0;
                                else break;
                        }

                        // I -> you, me -> you
                        for (int i = 0; i < pword.length(); i++) {
                                if (pword[i] == 'I') {
                                        if (i > 0 && (isdigit(pword[i-1]) || isalpha(pword[i-1]))) continue;
                                        else if (i < pword.length()-1 && (isdigit(pword[i+1]) || isalpha(pword[i+1]))) continue;
                                        pword = pword.substr(0, i) + "you" + pword.substr(i+1);
                                }
                        }
                        for (int i = 0; i < (int)pword.length()-1; i++) {
                                if (pword[i] == 'm' && pword[i+1] == 'e') {
                                        if (i > 0 && (isdigit(pword[i-1]) || isalpha(pword[i-1]))) continue;
                                        else if (i < pword.length()-2 && (isdigit(pword[i+2]) || isalpha(pword[i+2]))) continue;
                                        pword = pword.substr(0, i) + "you" + pword.substr(i+2);
                                }
                        }

                        // can you -> I can, could you -> I could
                        if (pword.length() >= 3 && pword.substr(pword.length() - 3) == "can" && word == "you") {
                                pword = pword.substr(0, (int)pword.length() - 3) + "I";
                                word = "can";
                        } else if (pword.length() >= 5 && pword.substr((int)pword.length() - 5) == "could" && word == "you") {
                                pword = pword.substr(0, (int)pword.length() - 5) + "I";
                                word = "could";

                        }

                        //加空格
                        if ((!isdigit(pword[0]) && !isalpha(pword[0])) || !f) {cout << pword; f = 1;}
                        else cout << ' ' << pword;

                        pword = word;
                }
                cout << endl;
        }

        return 0;
}

by SDUST weilinfox

本文地址:https://www.cnblogs.com/weilinfox/p/12545371.html

posted @ 2020-03-22 12:38  桜風の狐  阅读(327)  评论(0编辑  收藏  举报