找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 1854|回复: 6

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

[复制链接]

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24241 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
发表于 2022-9-5 17:56:39 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

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

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

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


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

cedict.png

内容还挺新的哈

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

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

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

caribe.png

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

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

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

CaribeReady.png

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

pip install googletrans==4.0.0rc1

reck.png

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

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

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

parse.png

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

madtran.png

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

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

  21.         # 先找拼音对应的,找不到就不管拼音了
  22.         def try_match_pinyin(expl):
  23.                 try:
  24.                         comments = expl[wpy]
  25.                 except KeyError:
  26.                         try:
  27.                                 comments = expl[wpyu]
  28.                         except KeyError:
  29.                                 # 找不到拼音对应,则进行拼音不匹配的方式查询
  30.                                 comments = []
  31.                                 for pron, comm in expl.items():
  32.                                         comments.extend(comm)
  33.                 return comments

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

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

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

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

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

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

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

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

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

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

downloader.png

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


QQ截图20220904235356.png

QQ截图20220905000302.png

QQ截图20220905003247.png

ew.PNG

nad.png

e.jpg

回复

使用道具 举报

0

主题

2

回帖

40

积分

用户组: 初·技术宅

UID
7824
精华
0
威望
2 点
宅币
34 个
贡献
0 次
宅之契约
0 份
在线时间
3 小时
注册时间
2022-5-3
发表于 2022-9-5 18:06:16 | 显示全部楼层
抢个沙发再看
回复 赞! 靠!

使用道具 举报

55

主题

275

回帖

9354

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
8219 个
贡献
251 次
宅之契约
0 份
在线时间
255 小时
注册时间
2014-2-22
发表于 2022-9-5 18:13:32 | 显示全部楼层
虽然不知道是干什么的,但感觉很厉害的样子。
回复 赞! 靠!

使用道具 举报

29

主题

315

回帖

1561

积分

用户组: 上·技术宅

UID
3808
精华
11
威望
105 点
宅币
702 个
贡献
165 次
宅之契约
0 份
在线时间
404 小时
注册时间
2018-5-6
发表于 2022-9-5 18:45:32 | 显示全部楼层
厉害了!python代码也很清晰,风格很喜欢!
另外插一句:这个帖子让弹幕流看到估计能腻歪死他哈哈哈哈哈哈哈哈哈哈
Passion Coding!
回复 赞! 靠!

使用道具 举报

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24241 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
 楼主| 发表于 2022-9-5 21:52:08 | 显示全部楼层
watermelon 发表于 2022-9-5 18:45
厉害了!python代码也很清晰,风格很喜欢!
另外插一句:这个帖子让弹幕流看到估计能腻歪死他哈哈哈哈哈哈 ...

我不觉得他看得懂,给他看他也不会腻歪。
回复 赞! 靠!

使用道具 举报

4

主题

36

回帖

667

积分

用户组: 大·技术宅

UID
7138
精华
0
威望
17 点
宅币
578 个
贡献
15 次
宅之契约
0 份
在线时间
63 小时
注册时间
2021-5-11
发表于 2022-11-2 21:50:49 | 显示全部楼层
不能用pypy加速,那用什么加速?Cython还是Numba
回复 赞! 靠!

使用道具 举报

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24241 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
 楼主| 发表于 2022-11-3 18:33:32 | 显示全部楼层
WeaponJang 发表于 2022-11-2 21:50
不能用pypy加速,那用什么加速?Cython还是Numba

不加速。
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-24 18:02 , Processed in 0.050938 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表