首先介绍一下词典软件。

目前最流行的还是有道词典、金山词霸等app。但是这些app在专业性和权威性上又有所不足。而Mdcit系列词典可以添加各种自定义词库,而且很多网友已经制作好了很多权威词典对应的Mdict词库(见Pdawiki与FreeMdict)。

而对于自己最常使用的macOS,支持Mdict词库的GoldenDict开发进度缓慢,界面不太好看,有时会遇到Bug。而另一款欧路词典需要收费才能添加自定义词库,而且界面、操作也不令人满意。

更新:欧路词典用户体验还可以。目前是常用的词典转换成macOS Dictionary格式使用,其它词典在欧路词典使用。毕竟每本词典都转换的话太费时间了。

相反,macOS系统原生的Dictionary有着良好的操作体验,支持三指取词,阅读体验也很棒,却没有那么多自定义词库可以添加。

于是,就想着把两者的优点结合起来,将丰富的Mdict词库转换成macOS Dictionary支持的格式,而且支持图片显示、发音等等功能。

下面简要简要记录由Mdict词库文件转换成完美macOS Dictionary词库文件的过程。

  • 所需环境

开源项目

PYGLOSSARY:最新Releases见ilius/pyglossary/releases

python-lzo:sudo pip3 install python-lzo

Writing to AppleDict: sudo pip3 install lxml beautifulsoup4 html5lib
GNU make as part of Command Line Tools for Xcode
Dictionary Development Kit as part of Auxillary Tools for Xcode. Extract to/Developer/Extras/Dictionary Development Kit

  • 转换过程

用PYGLOSSARY进行转换
假设词典文件为~/Downloads/oald8/oald8.mdx, 图片、语音文件oald8.mdd也在同一文件夹下。

先将词典文件转换成xml文件,并将其他图片、音频等文件提取出来放在OtherResources文件夹下。

cd ~/Downloads/oald8/
python3 ~/Software/pyglossary/pyglossary.pyw --read-options=resPath=OtherResources --write-format=AppleDict oald8.mdx oald8-apple
cd oald8-apple

在PYGLOSSARY的说明中接下来是将xml文件中的相对链接中的”/“去掉以及替换spx为wav。

sed -i "" 's:src="/:src=":g' oald8.xml
sed -i "" 's|sound://\([/_a-zA-Z0-9]*\).spx|\1.wav|g' oald8.xml

其实这两步可以在之后用正则统一替换。

  • 转换语音文件

如果是spx文件,先转换成wav(需安装speex)。若是wav文件则可跳过这一步。

find OtherResources -name "*.spx" -execdir sh -c 'spx={};speexdec $spx  ${spx%.*}.wav' \;

然后用FFmpeg把wav文件转换成mp3文件(macOS中默认的iTunes与QuickTime均不支持wav格式)。

在当前目录新建Sounds文件夹,并新建sh脚本convert.sh文件如下。

for x in ./OtherResources/*.wav; do ffmpeg -i "$x" "Sounds/`basename "$x" .wav`.mp3"; done

然后执行sh脚本。

sh ./convert.sh

如果语音文件较多的话需等待较长时间。

  • 编译
make

有时生成的词典包文件中并没有图片、音频文件。这时将OtherResources文件夹中除音频外的其他文件以及放置mp3文件的Sounds文件夹复制到xxx.dictionary/Contents目录下(右键dictionary文件,选择Show Package Contents)。

  • 安装
    将生成的dictionary文件复制到当前用户文件夹下的/Library/Dictionaries中(或者打开Dictionary App,选择菜单栏中的文件->打开词典文件夹,即可进入该文件夹),之后在Dictionary App的菜单栏中词典->偏好设置中启用一下就行。

  • 修正词典文件的各种问题
    以上方法生成的词典会有开头说到的词典内链接跳转不正常,不能发音、图片不能显示等种种小问题。下面修复这些问题。

  • Dictionary的URI Scheme介绍

以下引自Dictionary Services Programming Guide。

x-dictionary: is an URI scheme that describes cross references between entries in dictionaries. It is used in tag such as <a href="x-dictionary:r:another_id">.

The x-dictionary:URI contains three elements separated by colons as the general form—target selector, target text, and dictionary bundle ID. The target selector must be either d (for definition) or r (for reference). Use d if you want to search definitions of the following key text. Use r if you want to refer to the entry specified by the reference ID which must be unique to each dictionary.

x-dictionary:d:key_text:dict_bundle_id
x-dictionary:r:reference_id:dict_bundle_id
The dictionary bundle ID can be omitted in both forms, as shown in the following lines. If it is omitted, Dictionary Services searches the target text in all active dictionaries.
x-dictionary:d:key_text
x-dictionary:r:reference_id
  • 修复词典中的链接跳转问题

举例来说,假设dict_bundle_id为Longman5。(dict_bundle_id可在生成的词典文件中的Info.plist中修改。)

假设xml文件中为:

<a href="x-dictionary:d:entry://hour">hour</a>

可替换为:

<a href="x-dictionary:d:hour:Longman5">hour</a>

可用正则表达式匹配然后处理。

  • 修正词典中页面内的定位问题

例如点击apple1会跳转到同一个页面中的apple2处。

<a href="x-dictionary:d:entry://#_hke1">apple1</a>
<a name="_hke1">apple2</a>

将其替换为

<a href="#_hke1">apple1</a>
<a name="_hke1">apple2</a>
  • 修复词典的发音问题

假设xml文件中为:

<a href="x-dictionary:d:sound://1.spx"><img border="0" src="Br.gif"/></a>

可替换为

<audio id="1" src="Sounds/1.mp3"/><img border="0" src="Br.gif" onmousedown="document.getElementById('1').play(); return false;"/>

onmousedown可替换成onmouseover,这样鼠标悬浮上发音图标就开始发音,而不用单击。

可用正则表达式匹配然后处理。

  • Java正则替换代码示例

以Longman5_Activator为示例,假设只需要修复链接跳转问题和页面内的定位问题。写得比较随便,随意看一下就好。

当然挺多编辑器(比如Sublime Text、Visual Studio Code)直接支持正则表达式查找和替换,这样就不用写程序了。

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class Replace {static final String REGEX_1 = "x-dictionary:d:entry:\\/\\/#";static final String REGEX_2 = "entry:\\/\\/([^#\"][^\"]*)\"";static final String Bundle_Id = "Longman5_Activator";static final String inputName = "Longman5_Activator.xml";static final String outputName = "Longman5_Activator_Output.xml";static final String ENCODE = "UTF-8";BufferedReader br = null;BufferedWriter bw = null;public static void main(String[] args) throws IOException {new Replace().replaceFile();}public String replacefun1(String line) {Pattern pattern = Pattern.compile(REGEX_1);StringBuffer sbr = new StringBuffer();Matcher matcher = pattern.matcher(line);while (matcher.find()) {matcher.appendReplacement(sbr, "#");}matcher.appendTail(sbr);return sbr.toString();}public String replacefun2(String line) {Pattern pattern = Pattern.compile(REGEX_2);StringBuffer sbr = new StringBuffer();Matcher matcher = pattern.matcher(line);while (matcher.find()) {matcher.appendReplacement(sbr, matcher.group(1) + ":" + Bundle_Id + "\"");}matcher.appendTail(sbr);return sbr.toString();}public void replaceFile() throws IOException {try {br = new BufferedReader(new InputStreamReader(new FileInputStream(inputName), ENCODE));bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputName)));String line = null;while ((line = br.readLine()) != null) {bw.write(replacefun2(replacefun1(line)));bw.newLine();}} catch (IOException e) {} finally {bw.close();br.close();}}}
  • 其他注意事项

    • 文本匹配的正则表达式需一一调试

以上每个词典文件中的具体模式均不太一样,而且有时会有与一般模式不同的个例(如多加了几个空格、标签间加了个
、中间换了一行、图片大多是png个别是gif等等),需要一一调试。推荐调试网站Regexr。

- **空格相关问题**

连续两个粗体单词之间的空格会不显示。例如

<b>apple</b> <b>pie</b>

会显示为applepie。此时将其替换为

<b>apple</b>&#160;<b>pie</b>

注意xml中不能用&nbsp;

另外有时xml中会有&amp;nbsp;,原意应显示为空格,却显示为 。此时将其替换为 就好。

- **取词小窗口修改大小**

若取词小窗口中字体太小,可在词典包内容中的DefaultStyle.css文件中加上以下内容:

.apple_client-panel body{margin: 0 0 15px;font-size: 16px;}
 - **CSS样式文件**

若OtherResources文件夹中有其它CSS文件,或者原来CSS文件就独立于MDict文件之外,将其内容复制到词典文件包中的DefaultStyle.css文件中。

- **深色模式**

在深色模式中,转换的词典背景颜色依旧是白色,这可以通过修改词典包内容中的DefaultStyle.css文件解决。具体参考Make Mojave custom dictionaries work better。

- **其它问题**

@@@LINK=abc替换成<a href="x-dictionary:d:abc:dict_bundle_id">abc</a>。不过这样处理后显示的是指向另一个词条的链接,不是直接显示另一个词条。解决办法是扫描整个XML文件,将@@@LINK引用移动到正确的词条下。具体可以参考下述Python代码(引用自该链接)。

#!/usr/bin/env python3import xml.etree.ElementTree as ET'''
1. find the d:entry node which descendant contains the keyword "@@@LINK=" in text
2. parse the value behind "@@@LINK=" keyword and save it to variable title
3. save the index node belongs to the d:entry to variable index
4. find the d:entry node which title property exactly matches title
5. append index to the current d:entry node as child
6. remove the d:entry which descendant contains the keyword "@@@LINK="NOTE: please remove the default namespace from oald8.xml file manually before the script running and add it back when script done.
'''tree = ET.parse('./oald8.xml')
root = tree.getroot()ns = {'d': 'http://www.apple.com/DTDs/DictionaryService-1.0.rng'}
ET.register_namespace('d', 'http://www.apple.com/DTDs/DictionaryService-1.0.rng')# find all d:entry nodes which contains the keyword "@@@LINK=" in text
link_entries = root.findall('.//p/..', ns)for l_entry in link_entries:index = l_entry.find('./d:index', ns)title = l_entry.find('./p', ns).text.replace('@@@LINK=', '')entry = root.find('./d:entry[@d:title="' + title + '"]', ns)# remove l_entry directly if title cannot be found in entriesif entry is None:print(title)root.remove(l_entry)continue# append the index element to right entryentry.insert(0, index)
root.remove(l_entry)tree.write('oald8f.xml', 'UTF-8')

如果图片无法正常显示,将相对路径名最前面的/去掉,例如将<img src="/dir/abc.png"/>替换成<img src="dir/abc.png"/>.

由于macOS的Dictionary中鼠标悬浮于某一内容之上时会将其视作一个span,如果CSS中原本就有应用于所有span的样式,会把该样式应用于鼠标经过的区域。这样鼠标经过的区域会有很奇怪的样式。解决办法是在原有span中加一个class,并把原来span的样式归到新建的class中。

等等。

  • 其他功能

Dictinary还支持高亮搜索关键词、家长控制功能等等,参考之前提到过的Dictionary Services Programming Guide。

  • 与Alfred结合的一些功能

    • 快捷键取词

虽然三指轻点取词很方便,但是有些软件并不支持三指取词。结合Alfed Workflow即可实现选中待查内容后快捷键取词。

query="{query}"
word1="${query//\'/%27}"
word2="${word1// /%20}"
open dict://"$word2"
 - **快捷键发音**

下载韦氏142000单词发音库(密码:w4mw)后,假设解压至~/Voice文件夹下。同理即可实现选中待查内容后快捷键发音。

query="{query}"
char="${query::1}"
afplay ~/Voice/"$char"/"$query".wav

当然系统中开启Speech功能,结合快捷键也能实现类似功能。缺点是这是合成的发音而非真人发音,优点是单词变形乃至句子段落都能发音。

这里附上快捷键取词和快捷键发音的Alfred Workflow下载地址。​
更新:在单词中有空格或单引号时,原workflow失效。现在已修正。

  • Reference:

MAC OSX词典转换笔记
\BGL\DSL\MDX\CD\ ===> OS X dictionary

Mdict to macOS Dictionary转换笔记相关推荐

  1. 使用 conda 和 Jupyter 创建你的自定义 R 包,转换笔记为幻灯片

    创建你的自定义 R 包 出于用户使用方便考虑,Anaconda 已经在 "R Essentials" 中打包了一些最常用的数据科学 R 包.使用 conda metapackage ...

  2. 一个Json、数组、Dictionary转换和数组对比的C#实例

    最近做了一个程序,里面一段代码用到Json.数组.Dictionary转换和数组对比的一些知识,虽然在实际碰到类似问题时候有更好的方法,但这就当是一次基础知识的回顾,现在分享一下. 先介绍下要实现的业 ...

  3. 菜菜的刷题日记 | 蓝桥杯 — 十六进制转八进制(纯手撕版)附进制转换笔记

    系列索引:菜菜的刷题日记 | 被LeetCode用Python狂虐的那段日子 万万没想到啊,回老家过年断更的几天之后,我会因为无聊在除夕这天做了会儿题,然后写篇题解. 文章目录 [题目] [我的代码] ...

  4. 9277用计算机,关于计算机常用进制以及进制之间的转换笔记

    计算机常用进制以及进制之间的转换 进制的由来 生活中的常用进制 计算机中的二进制 计算机常用四种进制的说明 八进制和十六进制 进制之间的转换 进制的由来 进位就是进位计数制,就是一种计数的方法 古代社 ...

  5. 深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式

    环境: tensorflow1.15,cuda10.0,cudnn7.6.4 将keras训练好保存的.hdf5格式模型转为tensorflow的.pb模型,然后转为tensorrt支持的uff格式. ...

  6. macOS spacebar安装笔记

    简介 空格键是 macOS 的最小状态栏.非常适合与yabai等平铺窗口管理器一起使用. https://github.com/cmacrae/spacebar 安装 可以使用 Homebrew 从c ...

  7. macOS 开发 - 入门笔记

    文章目录 一些技巧 macOS 开发常用技术/框架 官方文档/教程 其它书籍教程等 OC 语言 Swift 语言 SwiftUI 框架 macOS 开发学习资源 视频教程 书籍 博客 Opensour ...

  8. ffmpeg视频格式转换笔记

    将YUV转换成h264 ffmpeg -s 176x144 -pixel_format yuv420p -i 176x144_pea_result.yuv -an -vcodec libx264 -b ...

  9. MacOS 驱动调试笔记

    1. 10.13 不可以在system下看到系统层的log了,要用log 命令来看, 如 1.1. log show --predicate 'process="kernel"' ...

  10. 将用int型存储的时间转换成time时间格式笔记

    设计了一套新的系统需要导入原有系统中的部分数据, 结果发现有个时间的字段跟原有的数据库设计不一样, 而且数据量不大,而且数据都在正式的数据库上面, 所以将数据导出到本地进行修改,然后统一导入, //文 ...

最新文章

  1. HTTP 错误 404.2 - Not Found
  2. 011 smali语法详解
  3. Spring Boot之 Configuration Annotation Proessor not found in classpath解决方法
  4. 洛谷 CF1043F Make It One 解题报告
  5. c语言中malloc、realloc与calloc 的区别以及联系
  6. 消费者广播模式和负载均衡模式
  7. pert计算公式期望值_PERT和三点估算技术
  8. HDU 1003 Maxsum
  9. 阿里云IoT将举办第三届极客创新挑战赛,吸引全球极客参赛
  10. ELK收集java日志
  11. 怎样得到对方的电脑名_吸引力法则让他想念你,让对方主动找你
  12. Ubuntu18.04无法进入图形界面桌面的问题及解决
  13. Linux网络服务之DHCP
  14. java 29期淘淘商城_JavaEE大型分布式电商项目 淘淘商城 29期
  15. 运营天猫商城的注意事项
  16. mac 右键 启动终端
  17. c语言log库,Log4g
  18. 从0到1快速了解netty长连接网关协议
  19. Selenium 2.0的由来及设计架构
  20. java语言程序设计教程课后题答案魏永红_《Java语言程序设计教程》习题参考答案...

热门文章

  1. FFmpeg[11] - ffmpeg去除水印(图片和文字)
  2. 关于SIM900A模块的学习心得
  3. 测试篇之一 sd卡独写速度测试
  4. Objective-c 开发环境
  5. 游戏场景设计探究:空间潜意识
  6. 那些年啊,那些事——一个程序员的奋斗史 ——18
  7. Python 实现Tracert追踪TTL值
  8. java 字符串占位符动态替换值工具类
  9. Android简易聊天室软件(HTTP实现)
  10. shark恒破解笔记3-EAX决定胜负