0xAA55 发表于 2022-9-5 17:56:39

【Python】编写莽夫翻译器!使用字典,进行按词翻译

项目源码:https://github.com/0xAA55/madtran

该莽夫式翻译可以模拟一个不会英文的人(手上却有中英字典)通过查字典进行逐词翻译,然后瞎几把选择释义(因为看不懂)造句。

造句后,句子很可能是语法不对的,于是使用现代赛博科技人工智能英语语法纠正器对句子的语法进行一个纠正。

前段时间,我在研究如何使用 Microsoft Sam 对 IPA 音标进行一个朗读的时候,接触到了 CEdict 中英字典。



内容还挺新的哈

既然它是个中英字典,那么使用它来编写按词翻译软件会怎么样呢?我感觉这甚至是可行的,翻译出来的结果会很生草。

但是在思路上,我感觉直接拿字典里的释义硬拼英文句子的做法,一定会产生语法不合理的句子,比如“I is ready”。Python 应该有库可以自动纠正英文句子(类似于 Grammarly 的作用)能得到“I am ready”这样的句子。

经过了一场针对 stackoverflow 的谷式搜索后,我找到了 Caribe 库,它确实具有一定的句子纠正效果:



于是我直接用 pip 安装!结果报错说没有 torch 可以用。再次搜索,发现 pypy 好像不能用 torch。老老实实用回 python 原版。

用 python 原版的时候,遇到 import _sqlite3 报错问题,这是因为我的 python 是使用 pyenv 安装的(虚拟环境),而安装的时候我没有装 libsqlite3-dev。这个 sqlite3 是 python 自带的模块,编译 python 前运行以下 sudo apt-get install libsqlite3-dev 安装这个库即可,python 在编译的过程中就能自动启用。

然后就搞定了 Caribe 用作我的语法纠错引擎。



在能够纠正句子的情况下,我们还需要能自动把生成的英文句子进行一个正经翻译,看翻译回来的中文是否离谱。这个时候我觉得可以想办法薅谷歌的羊毛,免费使用谷歌翻译。

pip install googletrans==4.0.0rc1



谷歌翻译也搞定了,接下来就是字典的部分,这部分就是得我亲自写代码实现了。

首先,我们要把 cedict.txt 处理为方便查字典的东西,比如 python 的 dict,但我不想每次都 parse 它,于是我先把它 parse 为 python 源码文件(类似于 json 的用法)然后使用 import 的方式来生成 __pycache__ 缓存的字节码 pyc 文件,这样重复使用的时候它加载会快一些。顺便输出一些 json 方便我本人亲自阅览。

顺带一提 parse 这个单词的发音谐音一种云南食物“啪饵丝”,也就是有点软烂的饵块切成丝



此处说一下总的翻译思路:瞎几把断句,只要断下来得到的词可以查到字典释义,就查。就这样处理一整个句子。如果遍历了所有可能的长度都查不到的话,那就放弃这个字符,从下一个开始。



查词的核心部分是 get_best_random_expl()。因为一个词是可以有多个释义的,而有的释义是“另见 xxx”,有的释义是“语素,用于表达xxx情况”等。这些东西都要处理,“另见 xxx”的内容要做重定向,而“语素”这些东西则要被过滤掉,避免其干扰翻译的结果。经过处理后,我使用 random.choice() 从多个释义里随机选择一个。

完整源码见本文开头。def get_best_random_expl(word):
        scwords = {word}
        try:
                scwords |= ctdict
        except KeyError:
                pass
        expl = lookup(word)
        if expl is None:
                return word, False
        wpy = " ".join( for p in pinyin(word, style=Style.TONE3, neutral_tone_with_five=True)])
        wpyu = wpy.upper()
        # 遍历查阅到的字典项,为进行大小写不敏感的拼音查找而复制出全大写的拼音项。
        upperlook = {}
        for pron, comments in expl.items():
                upron = pron.upper()
                if upron not in expl: upperlook = comments
        expl = {**expl, **upperlook}
        # 先找到所有相关的候选词
        cand = set()
        seealsos = set()

        # 先找拼音对应的,找不到就不管拼音了
        def try_match_pinyin(expl):
                try:
                        comments = expl
                except KeyError:
                        try:
                                comments = expl
                        except KeyError:
                                # 找不到拼音对应,则进行拼音不匹配的方式查询
                                comments = []
                                for pron, comm in expl.items():
                                        comments.extend(comm)
                return comments

        # 检查内容是不是需要的
        def check_comment(comment):
                nonlocal cand, seealsos
                # 去掉括弧里的内容
                comment = remove_parenthesis(comment).strip()
                if len(comment) == 0:
                        return

                # 去掉“particle”类型的解释,即语素描述
                if is_particle(comment):
                        return

                # 去掉“另见”,但是要记录另见什么。
                seealso = get_seealso(comment)
                if len(seealso):
                        seealsos |= seealso
                        return

                # 去掉其余不想要的内容
                if is_unwanted(comment):
                        return

                # 筛选需要的
                cand |= {comment}

        # 找到后,处理每一个解释项,删掉不要的解释项,并记录“另见”
        for comment in try_match_pinyin(expl):
                check_comment(comment)

        # 如果没有符合条件的选项,则看看有没有合适的“另见”
        # 先把“另见”里面与当前词相同的去除
        while len(cand) == 0:
                seealsos - scwords
                if len(seealsos) == 0:
                        break
                iter_seealsos = set(seealsos)
                for also in iter_seealsos:
                        alsoexpl = lookup(also)
                        if alsoexpl is None:
                                print("无用 also 内容:%s" % (also))
                                continue
                        for comment in try_match_pinyin(alsoexpl):
                                check_comment(comment)
                seealsos |= iter_seealsos

        # 如果还没有找到符合条件的选项(没有可用的 seealsos )则找相关词
        if len(cand) == 0:
                relateds = get_related_words(word)
                for related in relateds:
                        relatedexpl = lookup(related)
                        if relatedexpl is None:
                                print("无用 related 内容:%s" % (related))
                                continue
                        for comment in try_match_pinyin(relatedexpl):
                                check_comment(comment)

        # 如果相关词里也给不出候选项,则翻译失败,返回原单词。
        if len(cand) == 0:
                return word, False

        # 否则从剩下的候选项里,瞎几把挑一个。
        word = random.choice(list(cand))
        for wr in to_be_removed:
                word = word.replace(wr, '')
        return word, True最后做个字典的自动下载解压,基本就大功告成了。



为了能更方便地测试它的效果,我把它做成了 QQ bot 功能,可以在 QQ 群里调用。效果还是很喜人的。








退行了的倒影 发表于 2022-9-5 18:06:16

抢个沙发再看

Golden Blonde 发表于 2022-9-5 18:13:32

虽然不知道是干什么的,但感觉很厉害的样子。

watermelon 发表于 2022-9-5 18:45:32

厉害了!python代码也很清晰,风格很喜欢!
另外插一句:这个帖子让弹幕流看到估计能腻歪死他哈哈哈哈哈哈哈哈哈哈

0xAA55 发表于 2022-9-5 21:52:08

watermelon 发表于 2022-9-5 18:45
厉害了!python代码也很清晰,风格很喜欢!
另外插一句:这个帖子让弹幕流看到估计能腻歪死他哈哈哈哈哈哈 ...

我不觉得他看得懂,给他看他也不会腻歪。

WeaponJang 发表于 2022-11-2 21:50:49

不能用pypy加速,那用什么加速?Cython还是Numba

0xAA55 发表于 2022-11-3 18:33:32

WeaponJang 发表于 2022-11-2 21:50
不能用pypy加速,那用什么加速?Cython还是Numba

不加速。
页: [1]
查看完整版本: 【Python】编写莽夫翻译器!使用字典,进行按词翻译