# 基于规则的机器翻译系统
## 主要内容、目标
### 基本内容
基本内容由控制台版本实现, 代码对应附件: console version 文件夹可以从控制台录入 Markdown 格式的文本(只录入文本即可,无自由编辑功能),并保存生成 .md 文件: .
![](https://www.writebug.com/myres/static/uploads/2022/4/30/3b82246bc5cde0debb73f7bf157c6c1e.writebug)
图 1. 控制台录入 Markdown 格式运行截图
载入生成的 .md 文件,根据以上定义的 Markdown 语法子集进行解析,生成 HTML 文件(保证可以通过浏览器打开,正常展示): .
对于生成的 HTML 文件,无附带 CSS 样式,只生成基本的标签即可: .
![](https://www.writebug.com/myres/static/uploads/2022/4/30/2f725d73d30c5d8fb508050af19dbe12.writebug)
图 2. 程序运行后生成的未带 CSS 样式生成的 HTML 文件(Chrome 打开)
语法规则,Markdown 文本,HTML 标签等应合理表示: .
![](https://www.writebug.com/myres/static/uploads/2022/4/30/3b8584d460c54d9065a53745532d6fd3.writebug)
图 3. 深层嵌套 list(接下来会详述)
拓展部分实现内容
CSS 样式: .
![](https://www.writebug.com/myres/static/uploads/2022/4/30/ce2d19bcbd4066cb792c7610759eb7fa.writebug)
图 4. CSS 样式(以 Night.css)为例
附加语法(5 项): .
代码块:
![](https://www.writebug.com/myres/static/uploads/2022/4/30/36ec0dde87785095950477a1124b0999.writebug)
图 5. 附加语法: 代码块
行内代码块:
![](https://www.writebug.com/myres/static/uploads/2022/4/30/8d24ba47e86d2dee20a6fbbc52fd9a10.writebug)
图 6. 附加语法: 行内代码块
分割线:
![](https://www.writebug.com/myres/static/uploads/2022/4/30/965b09272d8ae5e7e512589c836421ed.writebug)
图 7. 附加语法: 分割线
引用语句块:
![](https://www.writebug.com/myres/static/uploads/2022/4/30/3cc0184a57ba49bbfcbf31e7825360d6.writebug)
图 8. 附加语法: 引用语句块
深层嵌套列表:
![](https://www.writebug.com/myres/static/uploads/2022/4/30/043df4ea19995de4667e9cb3634286db.writebug)
图 9. 深层嵌套列表
GUI 界面(自由编辑): .
![](https://www.writebug.com/myres/static/uploads/2022/4/30/8843949533b756c30395110a20f8cee9.writebug)
图 10. GUI
实现了基于 Qt5 的 GUI 界面, 可以自由编辑, 带来良好的用户交互体验,
![](https://www.writebug.com/myres/static/uploads/2022/4/30/7b0847948e723038343df4a58dd47b05.writebug)
图 11. 点击 GCmd2html 后截图
图 10 中下拉的菜单选项 GCmd2html(或者按快捷键 ctrl + G)就是 GC(gaocheng), Markdown 文件转 HTML 的选项, 点击后可以命名想要保存的文件名字, 当前编辑的内容即可转成 HTML 格式, 并保存在指定的文件夹下, 如图 11 所示.
#### 设计思路
本节介绍了基于面向对象思想, Markdown 文本解析并转换成 HTML 的设计思路. 详述了本次课设使用的核心方法: 基于位置优先的多层次分治算法模型.
首先学习 HTML 语言, 我们发现本次课设需要的可分为两种形式, 一是双端标记, 比如斜体:
```c++
*italic*, 加粗 **bold**;二是单端标记, 比如标题 # 一级标题等.
```
#### 如何解析复杂的嵌套句子
因为看到测试用例涉及复杂的嵌套 Markdown 解析, 并不可以暴力地把所有可能都列出来, 而且我们仔细分析发现暴力地列出所有可能情况, 强行地采用规则匹配, 对于嵌套的复杂格式处理能力很差, 这样看起来问题比较复杂, 如何设计一套对各种情况都能合法处理的自动化解析方式呢? 由嵌套, 首先想到的设计方法就是分治, ”分而治之”, 就是把一个复杂的问题分成两个或更多的相同或相似的子问题, 再把子问题分成更小的子问题, 直到最后子问题可以简单的直接求解.
从最简单的一个分治例子开始: 我们看如下简单嵌套 Markdown 语句递归树构成, 展示了一个 Markdown 应该以怎样的递归思路进行展开.
![](https://www.writebug.com/myres/static/uploads/2022/4/30/3273ec812d18fdb2d611a72aa470dfad.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/4/30/8ceafe59229f51eafa7cff86e84e3407.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/4/30/55e89da84ec16c5c80c113d2c1eae716.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/4/30/340a73c1ff782efd0650a2fd627e11ee.writebug)
#### 如何处理匹配标记的先后顺序
很容易我们就发现了一个问题, 不妨称每种标记格式(比如加粗, 斜体等)为一种格式环境, 当两个格式环境相互嵌套的时候, 或者出现多个环境同时并列的时候, 该如何进行匹配确定先后匹配顺序呢? 本次课设提出了基于位置优先的方法, 在每个 Markdown 语句中的匹配格式环境标记中, 优先匹配位置靠前的单端标记(比如标题等), 单端标记在分析后是可以被证明具有更高的优先级的, 然后再根据双端标记的 pair.first 优先级顺序进行解析与转换, 总是优先解析并匹配双端标记的第一个位置更前面的那个标记.
解析之后如果该解析的格式环境里面有其他嵌套的格式环境, 则像上图一样递归处理, 如果该解析的格式环境里有与其他格式环境产生交集的标记, 则所有存在交集的格式环境消亡. 这样就可以保证算法是鲁棒的.
对于某些错误的 Markdown 输入, 比如*这是含有交集的**两个*格式环境**, 像这样加粗环境和斜体环境产生了交集”两个”, 但是基于位置优先的分治算法模型不会出错, 不会存在 HTML 格式内出现环境交叉的情况.
综上所述, 我们依靠基于位置优先的分治算法已经可以对任何行进行处理, 但是在学习 HTML 后发现, 列表的格式环境是跨行的, 简单的行处理行不通. 注意, 无序<ul></ul>标记(或者有序<ol>标签)将与<li>标签一起使用, 但是又有差别, 下面就是一个典型的例子.
```c++
<ul>
<li>list item 1</li> <li>list item 2</li>
</ul>
```
每一个列表的 item 项需要<li>(每一个嵌套列表的周围也要包含<li>), 其实在列表的每一个层次递进中, <ul>和<li>都会被打上标记, 但是结束的时候, </li>是子列表要包含, 同级列表不用, 而</ul>是子列表和同级列表都需要包含. 这一点细微的差异怎么控制呢, 这就是算法模型的多层次的体现了, 算法通过一系列层次性的标志物, 保证了递归函数在回溯的时候都可以稳定地判断是否需要打<ul>或者<li>的标记, 保证了 HTML 语法的正确性.
#### 如何解析嵌套列表
![](https://www.writebug.com/myres/static/uploads/2022/4/30/374de1fefcc966a88107ced32c8bc2b9.writebug)
图 12. 复杂的嵌套列表
但是遇到嵌套列表该怎么做呢? 学习 HTML 之后发现嵌套列表其实是一个递归树的形式, 下面这个例子将展示这一思想(这是加强的测试用例, 很形象地展示了多层次算法模型的本质):
![](https://www.writebug.com/myres/static/uploads/2022/4/30/7d0b2a693da05f35be2a06d48b67b3ba.writebug)
图 13. 复杂的嵌套列表转化成递归树的形式
其实算法模型对列表的递归树做了一次先序遍历, 这样我们就把 HTML 语法转换成了我们容易理解的算法形式, 发现了解析一种语言的本质, 当然因为我还没学编译原理, 可能还有更厉害的方法, 但是这样多层次递归的解析, 已经是结构清晰明了, 效果稳定的方法了呢!
算法伪代码如下(LATEX 打得好辛苦!), 其实具体的实现, 回溯细节都是非常复杂和严谨, 这个算法模型结构简单, 但是具体实现可不一般.
Algorithm 1: 基于位置优先的多层次分治算法模型
```c++
Data:
Markdown text
Result:
HTML text
initialization;
```
##### 主要类�