1. 背景
最近在把一篇 Markdown 技术文章发布到 DFRobot 论坛时遇到一个实际问题:论坛编辑器不支持 Markdown 输入。
文章里包含标题、表格、列表、代码块、行内代码等结构。如果直接把 Markdown 原文粘贴到论坛,读者看到的是 # 、|---| 、反引号等 Markdown 标记,排版会明显变差。
后来验证发现,该论坛属于 Discuz/Comsenz 系论坛,BBCode 的兼容性更好。例如:
标题可以用 [size] 和 [b] 表示; 表格可以用 [table] 、[tr] 、[td] 表示; 代码块可以用 [code]...[/code] 表示; 列表可以用 [list] 或 [list=1] 表示。
因此,我把这套转换流程封装成了一个 Codex Skill,后续只要说“把这个 md 转成论坛 BBCode”,就可以复用同一套工具链。
2. Skill 的目标
这个 Skill 的目标不是实现完整的 Markdown 渲染器,而是解决一个很具体的问题:
> 将常见 Markdown 文档转换成 Discuz/论坛编辑器可接受的保守 BBCode,尽量保留文章结构。
设计时重点考虑以下几类内容:
Markdown 元素 BBCode 输出 # 标题[size][b]标题[/b][/size] fenced code block [code]代码[/code] Markdown 表格 [table] 、[tr] 、[td] 无序列表 [list] + [*] 有序列表 [list=1] + [*] 行内代码 [font=Consolas,monospace]代码[/font] 加粗 [b]文本[/b]
这个范围比较克制,但对技术文章来说已经覆盖了最常见的排版需求。
3. Skill 目录结构
创建后的 Skill 位于:
C:\Users\haili\.codex\skills\markdown-bbcode 复制代码
目录结构如下:
markdown-bbcode/
├── SKILL.md
├── agents/
│ └── openai.yaml
└── scripts/
└── md_to_bbcode.py 复制代码
其中:
SKILL.md 描述这个 Skill 何时触发、如何使用、转换规则和验证方式; agents/openai.yaml 提供界面侧展示信息; scripts/md_to_bbcode.py 是实际执行转换的 Python 脚本。
4. SKILL.md 的设计
Skill 的核心是 SKILL.md ,它通过 YAML frontmatter 告诉 Codex 这个 Skill 什么时候应该被使用。
关键描述如下:
---
name: markdown-bbcode
description: Convert Markdown documents into forum-friendly BBCode, especially for Discuz/Comsenz forums and editors that do not accept Markdown. Use when a user wants to publish a .md file to a forum while preserving headings, tables, lists, code blocks, inline code, and emphasis.
--- 复制代码
这里的 description 很重要,因为它决定了触发条件。为了提高命中率,描述里明确写了:
Markdown documents; forum-friendly BBCode; Discuz/Comsenz forums; editors that do not accept Markdown; headings、tables、lists、code blocks 等结构保留。
这样,当用户说“论坛不支持 Markdown,帮我转成 BBCode”时,Codex 就能较自然地选择这个 Skill。
5. 转换脚本的实现思路
脚本入口支持两个主要参数:
python "C:\Users\haili\.codex\skills\markdown-bbcode\scripts\md_to_bbcode.py" --input "D:\path\article.md" 复制代码
如果不指定输出路径,默认会在原文件同目录生成:
复制代码
也可以手动指定输出路径:
python "C:\Users\haili\.codex\skills\markdown-bbcode\scripts\md_to_bbcode.py" --input "D:\path\article.md" --output "D:\path\article.forum-bbcode.txt" 复制代码
脚本没有引入第三方依赖,只使用 Python 标准库:
argparse 用于解析命令行参数; pathlib 用于处理文件路径; re 用于识别 Markdown 结构。
这样做的好处是可移植性强,不需要额外安装包。
6. 核心状态机
转换过程采用一行一行扫描的方式,并维护几个简单状态:
in_code = False
code_lines = []
table_lines = []
list_kind = None
list_items = [] 复制代码
这些状态分别用于处理:
是否正在代码块中; 当前代码块的内容; 连续表格行; 当前列表类型; 连续列表项。
当遇到空行、标题、普通段落或其他结构时,脚本会先把已经缓存的列表或表格刷新到输出中。这种方式可以避免列表、表格被拆散。
7. 标题转换
Markdown 标题使用正则识别:
heading = re.match(r"^(#{1,6})\s+(.+)$", stripped) 复制代码
然后根据标题层级生成不同字号:
size = max(3, 7 - level)
out.append(f"[size={size}][b]{inline_bbcode(text)}[/b][/size]\n") 复制代码
例如:
复制代码
会转换为:
[size=5][b]2. Skill 的目标[/b][/size] 复制代码
8. 表格转换
Markdown 表格的行通常长这样:
| 项目 | 参数 |
|---|---|
| 工作电压 | DC 3.6V ~ 5.5V | 复制代码
脚本先判断一行是否像表格行:
def is_table_row(line: str) -> bool:
stripped = line.strip()
return stripped.startswith("|") and stripped.endswith("|") and stripped.count("|") >= 2 复制代码
再过滤掉分隔行:
def is_table_separator(line: str) -> bool:
cells = [cell.strip() for cell in line.strip().strip("|").split("|")]
return bool(cells) and all(re.fullmatch(r":?-{3,}:?", cell) for cell in cells) 复制代码
最后生成 BBCode:
[table]
[tr]
[td][b]项目[/b][/td]
[td][b]参数[/b][/td]
[/tr]
[tr]
[td]工作电压[/td]
[td]DC 3.6V ~ 5.5V[/td]
[/tr]
[/table] 复制代码
首行会自动加粗,用来模拟表头。
9. 代码块转换
Markdown 中的 fenced code block 使用三个反引号包裹:
Serial.begin(115200);
脚本遇到 `` 时切换 in_code` 状态。代码块内部不再解析 Markdown,而是原样收集,最后输出:
[code]Serial.begin(115200);[/code] 复制代码
同时,脚本会对方括号做转义,避免代码里的 [ 和 ] 被论坛误判成 BBCode 标签。
10. 列表转换
连续无序列表:
复制代码
会转换成:
[list]
[*] 智能灯光人体存在检测
[*] 房间无人节能控制
[/list] 复制代码
连续有序列表:
复制代码
会转换成:
[list=1]
[*] 安装库
[*] 上传程序
[/list] 复制代码
这里没有保留原始数字,而是交给 Discuz 的有序列表渲染。
11. 行内格式处理
行内格式由 inline_bbcode() 处理:
def inline_bbcode(text: str) -> str:
text = escape_bbcode(text)
text = re.sub(r"`([^`]+)`", r"[font=Consolas,monospace]\1[/font]", text)
text = re.sub(r"\*\*([^*]+)\*\*", r"[b]\1[/b]", text)
return text 复制代码
它主要处理三件事:
转义方括号; 把行内代码转换成等宽字体; 把 Markdown 加粗转换成 BBCode 加粗。
例如:
复制代码
会转换成:
官方示例默认串口波特率为 [font=Consolas,monospace]115200[/font]。 复制代码
12. 验证方式
Skill 创建完成后,先运行结构校验:
python "C:\Users\haili\.codex\skills\.system\skill-creator\scripts\quick_validate.py" "C:\Users\haili\.codex\skills\markdown-bbcode" 复制代码
通过后会输出:
复制代码
然后用真实 Markdown 文档实测:
python "C:\Users\haili\.codex\skills\markdown-bbcode\scripts\md_to_bbcode.py" --input "D:\Test\claudetest\C4002毫米波人体存在传感器接口协议与编程方法.md" 复制代码
再检查输出中是否包含关键标签:
Select-String -LiteralPath "D:\Test\claudetest\C4002毫米波人体存在传感器接口协议与编程方法.bbcode.txt" -Encoding UTF8 -Pattern '\[table\]|\[code\]|\[list' 复制代码
如果能看到 [table] 、[code] 、[list] 等标签,说明核心结构已经被转换出来。
13. 遇到的一个编码问题
在 Windows PowerShell 中写入 SKILL.md 时,如果使用某些 UTF-8 写法,文件可能带 BOM。某个校验脚本按系统默认编码读取时,可能出现类似错误:
UnicodeDecodeError: 'gbk' codec can't decode byte 复制代码
解决方式是把 SKILL.md 写成无 BOM UTF-8:
$enc = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText("C:\Users\haili\.codex\skills\markdown-bbcode\SKILL.md", $content, $enc) 复制代码
这个问题和转换逻辑本身无关,但在 Windows 环境下创建 Skill 时很值得注意。
14. 可扩展方向
当前脚本主要覆盖技术文章里最常见的 Markdown 结构。后续可以继续扩展:
支持 Markdown 链接转换为 [url] ; 支持图片转换为 [img] ; 支持引用块转换为 [quote] ; 支持删除线、斜体等更多行内样式; 支持不同论坛的 BBCode 方言; 增加 HTML 富文本输出,方便直接粘贴到富文本编辑器。
不过,对论坛发帖来说,保守转换通常比花哨转换更可靠。尤其是表格和代码块,只要能稳定保留,就已经能显著提升发帖效率。
15. 总结
这个 markdown-bbcode Skill 的价值在于把一次性的“Markdown 转论坛格式”操作沉淀为可复用能力。
它的设计思路比较简单:
用 SKILL.md 明确触发场景和使用流程; 用独立 Python 脚本保证转换过程稳定可重复; 只覆盖高频 Markdown 结构,避免实现过度复杂; 通过真实论坛稿件验证输出是否可用。
以后再遇到不支持 Markdown 的论坛,只需要把 .md 文件交给这个 Skill,就能快速得到适合粘贴到 BBCode/源码模式的发布稿。