C++实现一个简单的Markdown解释器

作者: SparkLiu | 来源:发表于2016-10-31 09:12 被阅读0次

    概要###

    这是一个在实验楼中找到的一个项目,用CPP写的Markdown解释器,具体要求可以点击这个网页查看

    简介

    在这个Markdown解释器中,采用的是文件输入输出流,将文件读入C++中然后进行字符串操作并输出成html文件

    实现的功能

    1. 处理多级标题
    2. 处理代码和代码块
    3. 处理多级引用
    4. 处理无序、有序列表
    5. 处理转义字符
    6. 处理粗体、斜体
    7. 处理分割线
    8. 处理超链接和图片

    运用的库

    • fstream
    • string
    • sstream
    • vector
    • stack
    • queue
    • regex

    项目结构

    • 程序文件
    • main.cpp
    • mdtransform.h
    • mdtransform.cpp
    • 待处理文件
    • test.md
    • 输出文件
      • index.html
      • my-markdown.css

    函数

    //mdtransform.h

    #ifndef MARKDOWNTRANSFORM_H
    #define MARKDOWNTRANSFORM_H
    class MarkdownTransform
    {
    public:
        MarkdownTransform(std::string);
        ~MarkdownTransform();
        std::string getContents();
        void process_title(std::vector<std::string>::iterator &, std::vector<std::string> & );//标题
        void process_code(std::vector<std::string>::iterator &, std::vector<std::string> &);//代码
        void process_refer(std::vector<std::string>::iterator &, std::vector<std::string> &);//引用
        void process_list(std::vector<std::string>::iterator &, std::vector<std::string> &);//列表
        void process_escape_first(std::vector<std::string>::iterator &, std::vector<std::string> & , std::queue<char>&);//转义字符
        void process_escape_last(std::vector<std::string>::iterator &, std::vector<std::string> &, std::queue<char>&);//转义字符
        void process_bold_and_italic(std::vector<std::string>::iterator &, std::vector<std::string> &);//粗体斜体
        void process_parting_line(std::vector<std::string>::iterator &, std::vector<std::string> &);//分割线
        void process_linebreak(std::vector<std::string>::iterator&, std::vector<std::string>&);//换行
        void process_emptyline(std::vector<std::string>::iterator&, std::vector<std::string>&);//处理空行
        void process_url(std::vector<std::string>::iterator&, std::vector<std::string>&);//超链接
        void process_image(std::vector<std::string>::iterator&, std::vector<std::string>&);//图片
        //辅助函数
        int assist_list(int, std::string);
        void change_list(int, std::vector<std::string>::iterator &,int);
    
        void split(std::string str, std::string limit, std::vector<std::string> &);
        std::string assist_url(std::string &, std::regex &, std::regex &, std::regex &);
        std::string assist_image(std::string &, std::regex &, std::regex &, std::regex &);
    
    private:
        std::string file_position;
    };
    
    #endif // !MARKDOWNTRANSFORM_H
    

    //mdtransform.cpp
    函数getContents()

    std::string MarkdownTransform::getContents()
    {
        std::string md2html_outfile = "";//最后输出的总文件
        std::ifstream fin;
        std::queue<char> charqueue;//用于辨别转义字符
        fin.open(file_position);
        if (fin.is_open())
        {
            std::string get_oneline;
            std::vector<std::string> totalstring;
    
            while (getline(fin, get_oneline))//连续获取fin中的一行,并把每一行添加到vector容器
            {
                totalstring.push_back(get_oneline);
    
            }
            int strveclen = totalstring.size();
            auto vit = totalstring.begin();
            process_escape_first(vit, totalstring,charqueue);
            process_code(vit, totalstring);//加入code标识符,必须最先,因为code中的东西无用
            process_list(vit, totalstring);
            process_parting_line(vit, totalstring);
            process_title(vit, totalstring); //加入h1~h5标识符,必须先于引用
            process_refer(vit, totalstring);
            process_bold_and_italic(vit, totalstring);
            process_image(vit, totalstring);
            process_url(vit, totalstring);
            process_linebreak(vit, totalstring);
            process_escape_last(vit, totalstring, charqueue);
            process_emptyline(vit, totalstring);
    
            for (auto ptr = totalstring.begin(); ptr != totalstring.end(); ptr++)
            {
                md2html_outfile += (*ptr) + '\n';
            }
            fin.close();
        }
        return md2html_outfile;
    }
    

    函数具体实现

    基本上所有的函数都是利用迭代器的二重循环去遍历文件然后对字符串做对应的修改

    std::vector<std::string>::iterator  viter;
    std::vector<std::string> totalstr;
    for (; viter != totalstr.end(); viter++)
        {
            std::string::iterator striter = (*viter).begin();
            if (!(*viter).empty())
            {
                for (; striter != (*viter).end(); striter++)
                {
                }
            }
        }
    
    • process_title中使用了计数器,记录title等级并写入h1~h5中
    • process_code中分为两种情况,一种是处理代码块,一种是处理行内代码
    • 处理代码块的时候用的是匹配字符串```,然后寻找下一行的```并保护其中的成员不被别的行数所修改
    • 处理行内代码是采用stack和counter判断应该添加什么html标记
    • process_refer用了stack处理多级引用
    • process_list用了三个函数,主函数是process_list
    • assist_list判断是有序列表还是无序列表
    • change_list修改行内内容,然后添加html标记
    • process_list用stack处理各种情况,并用flag标记一行的列表级数
    • process_escape用了两个函数
      • process_escape_first先把转义字符后面的那个字符压入queue
      • process_escape_last把queue中的字符逐一替代转义字符
    • process_bold_and_italic用了计数器去处理,0/1时输出不同的html标记
    • process_parting_line用了计数器
    • process_linebreak没啥好讲
    • process_emptyline同上
    • process_url用了三个函数,主函数是process_url
    • split是一个字符串分割函数,用了string的find()和substr()函数分割,并放入容器中
    • assist_url通过正则表达式处理最后的url并添加html标记
    • process_url定义各种正则表达式,然后遍历文件和对文件进行处理
    • process_image同process_url
    具体代码

    在github上面有具体代码,=-=其实代码写的挺啰嗦的,而且挺一般。

    码完这个Markdown解释器之后的感受

    1. 过程很艰难...
    2. debug很蛋疼,真正体会到design first,code later的重要性和好处
    3. 降低耦合性这些真的特别重要,一开始耦合度特别高,然后强行降低了,虽然最后还是有点耦合度的....
    4. 做个小项目,其实还是挺有趣的,对迭代器、对正则、对各种STL有了更深的理解
    5. 还有很多不足,还有很多没有实现的功能,例如高级的画表格。。。例如代码块识别出是JS/cpp/java/....例如超链接的另一种形式(下面代码)....例如蛋疼的换行问题(其实不同markdown解释器好像对换行实现都不大一样)。。。还顺带写了markdown的CSS
    [Google][link]
    [link]: http://www.google.com/ "Google"
    

    PS.实验楼这个网站上面的小项目好像挺多的

    相关文章

      网友评论

        本文标题:C++实现一个简单的Markdown解释器

        本文链接:https://www.haomeiwen.com/subject/uiauuttx.html