V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
huntzhan
V2EX  ›  Python

zhlint v0.3.2 发布,一个粗糙的中文 Markdown 文档风格检查器,开发过程的一点感想

  •  
  •   huntzhan ·
    huntzhan · 2016-10-06 18:01:31 +08:00 · 2797 次点击
    这是一个创建于 2752 天前的主题,其中的信息可能已经有所发展或是发生改变。

    关于这个玩具项目 huntzhan/zhlint,之前在已经在 V2EX 发过两个帖子了,前情提要:

    这个项目已经断断续续做了一个月了,从之前的 Demo ,到现在的粗糙成品,整个开发过程感触良多,发个贴分享一下。

    之前看到 DaoCloud 的写作规范和格式规范,突然觉得来了灵感,类比之前用过的 cpplint/flake8 等工具,既然中文文档的书写也有风格的定义,那必定是可以通过搞一个自动化工具来检测、修复文档风格的错误嘛!

    于是我撸起袖子简单计划了一下,觉得这个东西应该不算难,主要需要解决两个的问题就可以了:

    • 解析 Markdown 的语法格式。
    • 定义风格检测的规则。

    解析 Markdown 语法似乎简单,但深入之后有会遇到问题:

    • 如何提取每个 Markdown 语法元素?并保留语法元素的位置信息(行数与列数)?
    • 如何处理特殊的文档元素?如 line 、 table 、 LaTeX elements......
    • 有什么现成的工具可以支持我快速自定义一个 Markdown Parser 出来?

    经过一番调研,发现市面上的 Markdown Parser 都不能直接拿来用,无奈之下只能找一个看的顺眼的项目来 Hack 了。最终我选择的是 lepture/mistune,主要的原因是这个项目足够小,才一千行左右,改起来应该可以很快搞定。

    然而,事实上搞起来是挺痛苦的。一方面的原因,是 mistune 的解析行为主要由其定义的 regex 决定, regex 读起来相当痛苦,通过一边猜一边用 Debuggex 解析 regex 的方式,用了大概一天才把整个逻辑搞懂;另一个方面的原因是 mistune 在设计的时候并不 care 解析出来的 Markdown Element 的位置信息,为了得到这些信息我必须做一些奇奇怪怪的 Hack ,主要的耗时也在这一步。最终使用继承 mistune 基类的方式自己搞了个 Markdown Parser 出来。

    「 Parser 的部分搞定了,之后应该就是一帆风顺了吧,毕竟 Parser 的 Hack 应该是最脏的部分了。」这是我测完 Parser 的想法,现在看来还是太天真了。与检测、修复文档风格的逻辑相比, Parser 的部分「脏的程度」简直不值一提。

    为了检测文档风格错误,需要考虑:

    1. 由什么风格是需要检测的?
    2. 通过什么方式来检测?

    第一点还好,我仔细分析了 DaoCloud 的写作规范,提取了十余条可以自动化判断的规则,见支持的检查项目。然而,这些规则还是比较模糊的,当时没有仔细的思考每一条规则的边界条件,导致后续花费了很多时间在修 bug 上面。

    对于第二点,我打算用 regex 来搞,每一条规则定义出一些错误的 case ,然后用一组 regex 来命中这些 case 。

    "Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems." from Jamie Zawinski

    不说了,都是泪,各种边界条件搞不清楚,每次遇到新的无法处理的 case 只能手动把这个 case 泛化之后加进规则里,然后祈祷这条规则不会与其他规则冲突。而且 regex 里各种奇奇怪怪的用法也把我虐得半死,什么 non-capturing 、 look-ahead 、 look-behind 、 catastrophic backtracking ,非常可怕!

    就拿 E201 ,只有中文或中英文混排中,一律使用中文全角标点 这条规则为例。

    触发 E201 的、有风格错误的样例有:

    有中文, 错误.
    中文'测试'
    中文"测试"
    LaTeX 公式 $$.
    LaTeX 公式,$$
    LaTeX 公式 \(\).
    LaTeX 公式,\(\)
    

    正常的样例有:

    有中文,正确。
    有中文,正确......
    P.S. 这是一行中文。
    LaTeX 公式 $$
    LaTeX 公式 \(\)
    邮箱: [email protected]
    有中文, 1.0
    有中文, www.google.com
    链接地址 http://google.com
    

    要用 regex 来表达出这种差异,还是挺蛋疼的。

    万幸的是,这些坑我基本上都解决了。然而,通过这种类似「撞大运编程」搞出来的规则,我自己也不知道前面会有多少的坑,所以我在标题里讲 zhlint 是一个「粗糙的」中文 Markdown 文档风格检查器。反正 dog food 了一段时间之后感觉还是稳定的,已经能满足我自用的需求了,有什么问题以后慢慢再修。

    之后就是自动修复的功能了,这个其实还是比较简单的,直接跑一个 LCS 得到原始文本与 parsed 后文本的映射关系,然后把在 parsed 后文本的修改操作映射回原始 Markdown 文本即可。虽然这部分涉及的算法应该是最多的,但并没有花多少时间。

    总体的感想:

    1. 想要把一件事情做成,最重要的是 get your hands dirty ,硬着头皮怼。
    2. regex 真是坑啊!

    P.S. 本文已经过 zhlint 的风格检测。

    P.S. 有没有工程师愿意帮我搞 online demo 呀?zhlint-web 这个 demo 太丑了,而我又没点多少前端技能。

    P.S. 求靠谱内推。(其实这个项目是在面 DaoCloud 的过程中搞的,由于某些原因没有继续面下去)

    4 条回复    2016-12-01 14:38:06 +08:00
    aploium
        1
    aploium  
       2016-10-06 18:29:50 +08:00
    送你一颗星星~
    Python 里的正则超级好用的啊....只是 PyChrarm 的正则高亮对复杂正则来说基本是废的
    另外心疼一下 py2.x
    cheetah
        2
    cheetah  
       2016-10-07 10:45:30 +08:00 via iPhone
    good
    50vip
        3
    50vip  
       2016-12-01 14:34:51 +08:00
    楼主还在维护吗?
    huntzhan
        4
    huntzhan  
    OP
       2016-12-01 14:38:06 +08:00
    @50vip 打算重构
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   966 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 19:40 · PVG 03:40 · LAX 12:40 · JFK 15:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.