使用 java 实现一个简单的 markdown 语法解析器

1. 什么是 markdown

Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用。看到这里请不要被「标记」、「语言」所迷惑,Markdown 的语法十分简单。常用的标记符号也不超过十个,这种相对于更为复杂的HTML 标记语言来说,Markdown 可谓是十分轻量的,学习成本也不需要太多,且一旦熟悉这种语法规则,会有一劳永逸的效果。

2. 使用 java 实现一个简单的 markdown 语法解析器

markdown 语法解析器,可以实现将 markdown 语句转换成对应的 html 语句,之后由浏览器负责对 html 渲染。

2.1 markdown 标签简介

markdown 语法十分简单,常用的标签有:

代码        (```)
引用        (>)
无序列表    ('*','-','+')
有序列表    ('1.','2.','3.')
标题        (#)
图片        (![]())
链接        ([]())
行内引用    (`)
粗体        (**)
斜体        (*)
表格

具体的使用方式可以参见 Markdown——入门指南Markdown的基本语法

2.2 markdown 标签分类

  • markdown 标签可以简单分为 2 大类:一类是作用在多行语句或单行语句中的,如 代码、引用、无序列表、有序列表、表格等;另一类是只作用于单行语句中的,如 标题,图片,链接、行内引用、粗体、斜体等。
  • 其中,代码、引用、无序列表、有序列表、标题 这 5 类可以直接根据行首是否存在相应的标签直接进行判断这一行是否属于这些类型。如 行首元素为 '>' 可以直接判断这是一个引用行,行首元素为 '-' 可以直接判断这是一个无序列表行等。但需要注意的是,代码区域内不存在其他元素,即代码区域内的其他标签并不会被解析;而引用区域内可以存在其他元素,如 行首元素为 "> *" 可以判断此行为一个引用区域内的无序列表行。
  • 除了这 5 类标签外,图片,链接、行内引用、粗体、斜体这 5 类标签可以出现在行内的任意位置,于是要遍历一整行才可以解析出这 5 类标签。

2.3 markdown 解析器的实现

完整代码见 https://github.com/libaoquan95/MarkDownParser
已实现的 markdown 标签:代码、引用、无序列表、有序列表、标题、普通文本、图片、链接、行内引用、粗体、斜体
未实现的 markdown 标签:表格、tab多级结构

2.3.1 主体思路

主要思路是扫描 markdown 文件,对每一行进行标记,确定每一行的 markdown 标签,之后再根据每一行的 markdown 标签将 markdown 语句转换成 html 语句。

  • 第一次扫描 markdown 文件,定位 代码区引用区无序列表区有序列表区,因为这些标签均是可以作用于多行,要根据上下文的 markdown 标签才可以确定其作用范围。在这里需要特别注意 代码区 内不含其它区域,引用区 内可以嵌套其它区域。
  • 第二次扫描 markdown 文件,根据前一次扫描的定位结果,确定每一行 markdown 语句所对应的 markdown 标签。在这次扫描中可以确定 代码引用无序列表有序列表标题 这 5 类可以根据行首元素就能判定出类型的标签,所以不需要扫描全行。
  • 第三次扫描 markdown 文件,根据上一次的结果,可以直接将对应的 markdown 标签转换成 html 标签,此外要扫描全行,确定 图片链接行内引用粗体斜体 这 5 类元素并直接转换成 html。
2.3.2 读入 markdown 文件

扫描文件后,将文件按行存储至内存。相关成员变量如下:

// 按行存储 markdown 文件
private ArrayList<String> mdList = new ArrayList();
// 存储 markdown 文件的每一行对应类型
private ArrayList<String> mdListType = new ArrayList();

将 markdown 文件存入 mdList,之后多次扫描均是直接在 mdList 上进行修改。在本博客中,展示的事例的 markdown 文件如下

    ## 什么是 markdown 
    > Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者...

    ## markdown 常用标签:
    ```
    代码        (```)
    引用        (>)
    无序列表    ('*','-','+')
    有序列表    ('1.','2.','3.')
    标题        (#)
    图片        (![]())
    链接        ([]())
    行内引用    (`)
    粗体        (**)
    斜体        (*)
    表格
    ```
    ## markdown 入门1 
    1. [Markdown——入门指南](http://www.jianshu.com/p/1e402922ee32/)
    2. [Markdown的基本语法](http://www.cnblogs.com/libaoquan/p/6812426.html)

    ### markdown 标签分类
    - markdown 标签可以 **简单** 分为 2 大类:...
    - 其中,*代码*、`引用`、无序列表、有序列表、标题这 5 类...
    - 除了这 5 类标签外,图片,链接、行内引用、粗体、斜体这 5 类...
2.3.3 第一次扫描

在这次扫描中,可以确定出 代码区 定位标签 CODE_BEGIN 和 CODE_END,引用区 定位标签 QUOTE_BEGIN 和 QUOTE_END,无序列表区 定位标签 UNORDER_BEGIN 和 UNORDER_END,有序列表区 定位标签 ORDER_BEGIN 和 ORDER_END。而其他语句在此次扫描中均暂时定义为 OTHER。

/**
 * 判断每一段 markdown 语法对应的 html 类型
 * @param 空
* @return 空
 */
private void defineAreaType() {
    // 定位代码区
    ArrayList<String> tempList = new ArrayList();
    ArrayList<String> tempType = new ArrayList();
    tempType.add("OTHER");
    tempList.add(" ");
    boolean codeBegin = false, codeEnd = false;
    for(int i = 1; i < mdList.size() - 1; i++){
        String line = mdList.get(i);
        if(line.length() > 2 && line.charAt(0) == '`' && line.charAt(1) == '`' && line.charAt(2) == '`') {
            // 进入代码区
            if(!codeBegin && !codeEnd) {
                tempType.add("CODE_BEGIN");
                tempList.add(" ");
                codeBegin = true;
            }
            // 离开代码区
            else if(codeBegin && !codeEnd) {
        
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值