B3927 / String Simulation

小杨的字典

这题本质上只做一件事:从左到右扫一遍文章。字母先装进小口袋,碰到标点就把口袋里的单词拿去查字典,再把标点原样输出。

一句话概括 看到字母就继续拼单词,看到标点就结算这个单词。
如果字典里没有,就翻译成 UNK
规则 1:连续字母属于同一个单词。
规则 2:标点不翻译,直接照抄。
规则 3:末尾补一个空格,防止漏掉最后一个单词。

思路拆成 3 步

讲课时可以一直围绕这三步来板书,学生不容易乱。

01

收集字母

如果当前字符是小写字母,就把它接到 word 后面。也就是说,word 始终保存“当前还没处理完的单词”。

a -> word b -> word c -> word = abc
02

遇到标点就结算

只要遇到标点,说明前面的单词结束了。先拿 word 去字典里找翻译,输出后清空 word,再把标点自己输出。

03

查不到就输出 UNK

字典最多只有 100 条,直接顺序查找就够了。如果从头到尾都没找到,就输出大写 UNK

样例演示

下面用题目的经典样例 abc.d.d.abc.abcd. 来看程序是怎么一步步翻译的。

当前读到

还没开始

口袋里的单词 word

这一步发生了什么

点击“下一步”开始演示。

当前输出结果

abc -> a d -> def 不在字典 -> UNK

参考代码

这里保留了信奥里更常见的写法:普通下标循环、数组存字典、顺序查找,不用 foreach,更容易跟着讲。

#include <bits/stdc++.h>
using namespace std;

string a[105], b[105];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i] >> b[i];
    }

    string s;
    cin >> s;
    s += ' ';  // 哨兵,保证最后一个单词也会被处理

    string word = "";
    for (int i = 0; i < (int)s.size(); i++) {
        char ch = s[i];
        if ('a' <= ch && ch <= 'z') {
            word += ch;
        } else {
            if (word != "") {
                int pos = 0;
                for (int j = 1; j <= n; j++) {
                    if (a[j] == word) {
                        pos = j;
                        break;
                    }
                }

                if (pos == 0) cout << "UNK";
                else cout << b[pos];

                word = "";
            }

            if (ch != ' ') {
                cout << ch;
            }
        }
    }

    return 0;
}