如何用纯Jinja2实现Markdown文档的二级编号(1、2a格式)
纯Jinja2实现Markdown二级自动编号解决方案
问题根源分析
你之前的两个方案存在三个核心问题:
- 变量作用域限制:Jinja2宏内部的
{% set %}默认创建局部变量,无法修改外部定义的number和sub_number,导致主编号始终不递增,子编号逻辑完全混乱。 - 依赖Python内置函数:方案2中使用的
chr()/ord()并非Jinja2默认提供的工具,直接调用会报错。 - 子编号转换逻辑错误:方案1中把字符
'a'转为整数会得到0,后续递增后变成数字字符串,完全偏离字母子编号的需求。
标准解决方案(区分一级/二级标题)
使用Jinja2的namespace对象维护全局状态,配合字母列表实现纯Jinja2的子编号递增,无需依赖外部函数。
完整实现代码
{% set ns = namespace(main_num=1, sub_idx=0, letters=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']) %} {# 生成一级编号(如1、3) #} {% macro main_heading() -%} {{ ns.main_num }} {%- set ns.main_num = ns.main_num + 1 %} {%- set ns.sub_idx = 0 %} {# 重置子编号索引 #} {%- endmacro %} {# 生成二级编号(如2a、2b、4a) #} {% macro sub_heading() -%} {{ ns.main_num - 1 }}{{ ns.letters[ns.sub_idx] }} {%- set ns.sub_idx = ns.sub_idx + 1 %} {# 子编号到z后,自动递增主编号并重置子索引 #} {%- if ns.sub_idx >= ns.letters|length %} {%- set ns.main_num = ns.main_num + 1 %} {%- set ns.sub_idx = 0 %} {%- endif %} {%- endmacro %}
调用示例
# {{ main_heading() }} 一级标题1 ## {{ sub_heading() }} 二级标题2a ## {{ sub_heading() }} 二级标题2b ## {{ sub_heading() }} 二级标题2c # {{ main_heading() }} 一级标题3 ## {{ sub_heading() }} 二级标题4a
渲染结果
# 1 一级标题1 ## 2a 二级标题2a ## 2b 二级标题2b ## 2c 二级标题2c # 3 一级标题3 ## 4a 二级标题4a
混合编号实现(自动切换1、2a、2b、3、4a格式)
如果需要无需手动区分一级/二级,自动生成混合编号,可使用以下逻辑:
完整实现代码
{% set ns = namespace(current_main=1, sub_idx=-1, letters=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']) %} {% macro auto_number() -%} {%- if ns.sub_idx == -1 %} {# 生成主编号 #} {{ ns.current_main }} {%- set ns.sub_idx = 0 %} {%- else %} {# 生成二级编号 #} {{ ns.current_main }}{{ ns.letters[ns.sub_idx] }} {%- set ns.sub_idx = ns.sub_idx + 1 %} {# 子编号到z后切换主编号 #} {%- if ns.sub_idx >= ns.letters|length %} {%- set ns.current_main = ns.current_main + 1 %} {%- set ns.sub_idx = -1 %} {%- endif %} {%- endif %} {%- endmacro %} {# 手动切换到下一个主编号(用于提前结束子编号组) #} {% macro next_main() -%} {%- set ns.current_main = ns.current_main + 1 %} {%- set ns.sub_idx = -1 %} {%- endmacro %}
调用示例
## {{ auto_number() }} 标题1 ## {{ auto_number() }} 标题2a ## {{ auto_number() }} 标题2b ## {{ auto_number() }} 标题2c {{ next_main() }} ## {{ auto_number() }} 标题3 {{ next_main() }} ## {{ auto_number() }} 标题4a
渲染结果
## 1 标题1 ## 2a 标题2a ## 2b 标题2b ## 2c 标题2c ## 3 标题3 ## 4a 标题4a
内容的提问来源于stack exchange,提问作者Nosail
相关产品推荐
相关产品推荐

