reStructuredText 专题
本文最后更新于 2022年10月3日 凌晨
引子
对许多开发者来说,Markdown 这种标记语言在写作、特别是编写技术文章时非常好用:无需为字体、字号、行间距等不重要的样式问题分心,而标题、列表、引用、图片、代码段等又可通过语法指明语义。
事实上,Markdown 并非唯一的常用标记语言。在 Python 圈内,常常会见到以 .rst
为扩展名的文档:Python 官方文档、Flask 文档、django 文档、pandas 文档、RAY 文档……几乎所有能想到的优秀项目的文档都是由另一种强大的标记语言写成的。它就是 reStructuredText。
注意,reStructuredText 是一个单词,而不是两个!
简介
reStructuredText 是一个易于阅读的、所见即所得的纯文本标记语法与解析器系统。它适用于内联程序文档(例如 Python 文档字符串)、快速创建简单的网页和独立文档。reStructuredText 是为特定应用程序域的可扩性而设计的。reStructuredText 解析器是 Docutils 的一个组件。reStructuredText 是对 StructuredText 和 Setext 轻量标记系统的修订和重新解释。
reStructuredText 的主要目标是定义和实现一种标记语法,用于 Python 文档字符串和其他文档领域,这种语法可读性强、简单,但又足够强大,可用于非凡的用途。标记的预期目的是将 reStructuredText 文档转换为有用的结构化数据格式。
它具有以下特点:
- 简洁:解析前的纯文本仍具有良好可读性。
- 强大:强大的 role、directive 以及扩展系统可以极大地增强表达能力。
- 统一:不论是任何平台,其解析功能都统一在 docutils 模块下。
常用语法
reStructuredText 语法大致分为两部分:
- 基本语法:实现段落、列表、标题等基本功能
- 指令(Directives):实现插入图像、从 CSV 生成表格、生成目录、甚至 “运行 Python 代码或借用进程间通信机制调用其他代码,并将结果嵌入输出中” 等复杂功能
除特别声明外,reStructuredText 中使用 3 个空格表示 1 个缩进。
本节将介绍常用语法,建议阅读以下内容以获取更多信息:
项目 | 描述 |
---|---|
入门 reStructuredText — Learn reStructureText 2.0.0 文档 | 很不错的中文入门教程 |
Quick reStructuredText | 简单清晰的源码与解析效果对比 |
reStructuredText Markup Specification | 详尽语法细节,适合深入研究 |
段落(Paragraphs)
由空行分隔的文本块为一个段落。段落必须有相同的缩进。段落内即使有换行,也仍会被解析为同一个段落。
1 |
|
有些情况下,期望能保留源代码中的换行情况,又不希望被拆分为多个段落。这时可以在行首使用管道符 |
来创建 line block:
1 |
|
内联标记(Inline markup)
在段落和其他块元素内,可以使用内联的文本记号来为某个片段的文本标记语义。不同的语义常被渲染为不同的样式,例如 *着重*
默认被渲染为 斜体、**强调**
默认被渲染为 粗体。
实际上,这些内联标记都是 [reStructuredText 角色](Creating reStructuredText Interpreted Text Roles (sourceforge.io)) 的简写。
注意标记符号与被包裹的文本内容之间不能存在空格,与外部文本之间必须存在空格。
着重(emphasis)
用一对单星号表示着重,对应 HTML 中的 <em>
,一般用斜体表示。
1 |
|
强调(strong)
用一对双星号表示强调,对应 HTML 中的 <strong>
,一般用粗体表示。
1 |
|
字面量(literal)
用一对双反引号表示字面量
,实际上为 literal
角色,对应 HTML 中的 <pre>
预定义格式文本,常用作 “行内代码” 的表示方法。
1 |
|
列表(Lists)
- 首末项与上下文间需要空行,列表项之间无需空行。
- 列表中使用两个空格作为一个缩进。
- 嵌套子列表时,子列表的首末项与父列表的项目间需要用空行分隔。
- 有序列表与无序列表可以相互嵌套、多层嵌套。
无序列表(Bulleted lists)
使用 -
、+
或 *
创建无序列表。
1 |
|
无序列表的项目符号可以混用(虽然不建议这样做),只需保持缩进一致即可。
有序列表(Enumerated lists)
许多符号均可创建有序列表(如 a.
、A.
、I.
、1)
、(1)
等),但最常用的是数字
+ .
(手动编号)和#
+ .
(自动编号)两种方式:
1 |
|
1 |
|
定义列表(Definition lists)
定义列表将术语与定义相关联。
1 |
|
标题/章节(Sections)
reStructuredText 并不像 Markdown、HTML 那样用一种固定的语法表示各级标题,而是将所有 “标题装饰字符” 标记出的文本视为标题。解析器遇到的第一种标题样式将作为一级标题,第二种作为二级标题……依次类推。这种设计的便捷之处在于可以随时插入新的标题级别。
标题层级数没有限制(虽然导出为 HTML 或其他格式时往往最多支持 6 级标题),但建议写作时避免使用 5 级甚至更深的标题。
有效的标题装饰字符很多,其中建议使用以下项作为标题的 “下划线” 或 “上下划线” 以修饰:
1 |
|
以下为部分标题样式示例 :
1 |
|
表格(Tables)
reStructuredText 语法支持网格表、简单表两种表格形式。通过指令还可以创建 CSV 表、List 表等。
网格表(Grid tables)
功能较强的表格,必须手动 “画” 出单元格:
1 |
|
简单表(Simple tables)
更简单紧凑,但功能有限:必须包含多个行,且第一列单元格不能包含多行。
1 |
|
CSV 表(CSV tables)
使用 csv-table
指令可以从 CSV 数据创建表格。
1 |
|
列表表(List tables)
使用 list-table
指令,可以用列表的形式创建表格。列表的顶级项表示一行,次级项表示一行的各元素:
1 |
|
图像(Images)
使用 image
指令、figure
指令插入图像,还可以通过选项进行调整。二者区别在于:
- image 直接插入图片。
- figure 由 image 、一段标题(一个单行段落)和(可选的)图例组成。对于基于页的媒体(如 PDF),在排版时 figure 可能会浮动到合适的地方。
image
简单用法举例:
1 |
|
image
较详细用法举例:
1 |
|
各属性含义可以参考此文。
超链接(Hyperlinks)
在 reStructuredText 中,一个超链接由引用和靶标两个部分组成:
可以使用目标定义的形式,将引用和靶标分离:
1 |
|
引用和靶标也可以写在同一处(内联网页链接):
1 |
|
符合规则的 URI 也会自动被解析为超链接,文本与链接本身相同。例如:
1 |
|
将被解析为如下 HTML:
1 |
|
代码段(Code)
使用 code
指令创建。
1 |
|
如果指定了编程语言,则会由 Pygments 语法高亮器处理解析。
TODO
脚注(Footnotes)
TODO
更多信息,请参阅文档。
目录(Contents)
使用 contents
指令即可生成本文的目录,类似于某些 Markdown 解析器提供的 TOC
扩展语法。
1 |
|
可选参数及更多信息,请参阅文档。
警告(Admonition)
可以使用 admonition 下的具体某一个指令来创建一条警告/提示消息。
编辑器
虽然使用任何纯文本编辑器均可完成 reStructuredText 源代码的编写,但期望在编辑时能有语法高亮、自动补全、预览等功能。
安装插件后的 VS Code 可以很好地实现上述功能。
reStructuredText Extension for Visual Studio Code on Strikingly
TODO
reStructuredText vs Markdown
优缺点
相比流传广泛的 Markdown,reStructuredText 具有更好的表达能力、扩展能力以及稳定性。 Markdown 根据其扩展标准、具体实现、使用环境的不同,有多个社区提供了不同的 Markdown 支持。 在具有丰富生态的同时,也陷入了生态分裂的窘境。
由于使用 Markdown 不可避免的表现力不足的缺点,各个实现往不同的方向寻找扩展方法。 有的 Markdown 使用
{% parameters %}
形式的 shortcode 来提供扩展,如 markdown-it; 有的 Markdown 将额外的功能写入解析器,如最为强大的 pandoc; 有的 Markdown 试图添加新的语法,例如 latex 风格的指令。但它们的生态是分裂的,在前者提供的扩展,后者可能未提供,或者以另一种形式提供, 导致文档难以迁移。
而 reStructuredText 在这一方面拥有巨大的优势:它以及提供了一个完善的扩展开发环境。 任何表达都可以通过统一的 role 或 directive API 来实现!
相互转换
可以使用工具 Pandoc 实现这两种语言间的相互转换。虽然不可避免地会丢失一些非共有的特性和细节,但完全可以胜任日常简单文档的格式转换。
查看 Pandoc 文档的安装页面,最简单的安装方式为:前往 GitHub Releases 页面下载适合自己操作系统的最新版安装包即可。完成安装后,pandoc
命令已被添加至系统环境变量,可以在任意位置使用。
最简单的使用方式如下:
1 |
|
更多信息,请参阅 Pandoc 用户手册。
Sphinx
实际上,本文正是为介绍 Sphinx 做铺垫。
参考资料
reStructuredText Markup Specification
Learn reStructureText 2.0.0 文档
Sphinx reStructuredText 语法入门 — MegEngine 文档
碎碎念
精巧的标记语言
reStructuredText 这篇博文的写作难度远高于预期。本以为简单复制粘贴整理一些 “基本语法”,加上简单介绍即可。然而真正开始阅读 Markup Specification 等详尽文档说明时,渐惊讶于 “角色”、“指令” 等精巧的设计和非常丰富的功能。这次学习之旅不仅仅掌握了一门标记语言的基本用法,更初步领略到了标记语言背后复杂精妙的设计、权衡。
Pyject 首次预告
reStructuredText 正是对 Sphinx、Read the Docs 这一组 Python 项目文档编写托管工作流的铺垫。而文档工作流,以及之前所写的代码格式化工具 Black、虚拟环境与依赖管理工具 Poetry、静态类型检查工具 Mypy 等等,其实都是一个大型项目 Pyject
的组成部分。
Pyject
为 Python Project
的缩写,旨在为进行大型多人合作的 Python 项目中可能遇到的非代码编程问题(文档编写、代码风格、版本控制、依赖管理、静态类型检查……)提供指引,介绍对应的工具以解决这些问题。
显然,Pyject 的内容非常之多,目前已完成的部分也较为独立,相互间缺乏整理联系,还有很长的路要走。计划在 “文档编写与托管” 这一部分初稿完成后,创建 GitHub 仓库,并开始将已完成的文章进行整合与查漏补缺。