在维护大型文档项目(如技术手册、博客仓库、知识库)时,你是否曾遇到以下痛点?
- 需要将所有  图片链接批量替换为新 CDN 地址;
- 想从上百篇 .md 文件中提取所有标题,生成目录索引;
- 团队提交的 Markdown 存在格式不规范(如空行缺失、标题未对齐),需自动校验。
手动逐个修改?效率低下且易出错!
本文将教你如何利用 正则表达式(Regex) + Python 脚本,高效完成 Markdown 文件的批量替换、内容提取与格式校验,并提供可直接运行的代码模板,助你实现“一键自动化”!
一、为什么选择正则表达式处理 Markdown?
虽然 Markdown 是结构化文本,但其语法简单、规则明确,非常适合用正则进行模式匹配。相比解析 AST(如使用 markdown-it),正则方案具有:
- 轻量快速:无需依赖重型解析库;
- 灵活可控:精准定位特定模式;
- 易于集成:一行命令或脚本即可执行。
注意:正则不适合处理嵌套结构(如表格内含代码块),但对于 90% 的日常任务(链接、图片、标题、代码块等)完全够用。
二、常用 Markdown 元素正则模式速查表
| 一级标题 | ^# (.+)$ | 匹配 # 标题 |
| 二级标题 | ^## (.+)$ | 匹配 ## 子标题 |
| 图片 | !$$([^$$]*)$$$([^)]+)$ | 提取 alt 和 url |
| 超链接 | $$(.+?)$$$(https?://[^)]+)$ | 匹配外部链接 |
| 行内代码 | `([^`]+)` | 匹配 `code` |
| 代码块 | (\\w+)?\\n([\\s\\S]*?)\\n | 匹配带语言标识的代码块 |
| 无序列表 | ^[-*+] (.+)$ | 匹配 – item |
| 任务列表 | ^- $$([ x])$$ (.+)$ | 提取状态与内容 |
小技巧:在 regex101.com 上测试你的正则,选择 Python Flavor。
三、实战场景 1:批量替换图片链接(迁移 CDN)
需求
将所有本地图片路径 ./images/xxx.png 替换为 CDN 地址 2026-02-1320ith0etzle.png。
正则思路
- 匹配图片 URL 中包含 ./images/ 的部分;
- 保留文件名,替换前缀。
Python 脚本
import re
import os
import glob
def replace_image_links(md_file, old_prefix="./images/", new_prefix="https://cdn.example.com/blog/"):
with open(md_file, 'r', encoding='utf-8') as f:
content = f.read()
# 正则:匹配图片URL中old_prefix开头的部分
pattern = r'!$$([^$$]*)$$$' + re.escape(old_prefix) + r'([^)]+)$'
repl = r''
new_content = re.sub(pattern, repl, content)
with open(md_file, 'w', encoding='utf-8') as f:
f.write(new_content)
# 批量处理所有 .md 文件
for md_file in glob.glob("docs/**/*.md", recursive=True):
replace_image_links(md_file)
print(f"已处理: {md_file}")
关键点:
- 使用 re.escape() 避免特殊字符干扰;
- \\1, \\2 引用捕获组,保留 alt 文本和文件名。
四、实战场景 2:提取所有标题生成目录
需求
扫描整个项目,提取所有 #、##、### 标题,输出层级化目录。
Python 脚本
import re
import glob
def extract_headings(md_file):
with open(md_file, 'r', encoding='utf-8') as f:
lines = f.readlines()
headings = []
for line in lines:
if line.startswith('#'):
level = line.count('#')
title = line.strip('# \\n')
headings.append((level, title))
return headings
all_headings = []
for md_file in glob.glob("posts/*.md"):
headings = extract_headings(md_file)
all_headings.extend(headings)
# 输出 Markdown 目录
for level, title in all_headings:
indent = " " * (level – 1)
print(f"{indent}– [{title}](#{title.lower().replace(' ', '-')})")
输出示例:
– [入门指南](#入门指南)
– [安装步骤](#安装步骤)
– [基本配置](#基本配置)
– [高级用法](#高级用法)
五、实战场景 3:校验 Markdown 格式规范
常见规范要求
- 标题前后必须有空行;
- 图片必须包含非空 alt 文本;
- 不允许连续两个以上空行。
校验脚本(部分)
import re
def validate_markdown(md_file):
with open(md_file, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\\n')
errors = []
# 规则1: 标题前后需空行
for i, line in enumerate(lines):
if line.startswith('#'):
if i > 0 and lines[i–1].strip() != '':
errors.append(f"L{i+1}: 标题前缺少空行")
if i < len(lines)–1 and lines[i+1].strip() != '':
errors.append(f"L{i+1}: 标题后缺少空行")
# 规则2: 图片 alt 文本不能为空
empty_alt = re.findall(r'!$$$$$[^)]+$', content)
if empty_alt:
errors.append("存在空 alt 文本的图片")
# 规则3: 禁止连续3个以上空行
if re.search(r'\\n\\s*\\n\\s*\\n\\s*\\n', content):
errors.append("存在连续3个以上空行")
return errors
# 执行校验
for md_file in glob.glob("*.md"):
errs = validate_markdown(md_file)
if errs:
print(f" {md_file} 发现问题:")
for e in errs:
print(f" – {e}")
可集成到 CI 流程,在 Git 提交前自动检查。
六、高级技巧:处理多行模式与贪婪匹配
问题:代码块跨多行,如何精准匹配?
# 正确写法:使用 [\\s\\S] 匹配任意字符(包括换行)
code_block_pattern = r'```(\\w+)?\\n([\\s\\S]*?)\\n```'
问题:避免过度匹配(如多个图片连在一起)
- 使用非贪婪匹配 .*? 而非 .*
- 示例:$$(.*?)$$$(.*?)$ 而不是 $$(.*)$$$(.*)$
七、工具推荐:无需编程也能用正则
- VS Code: Ctrl+Shift+H 全局搜索替换,支持正则(勾选 .* 图标)
- Notepad++: 查找 → 替换 → 勾选“正则表达式”
- 在线工具: RegExr、Text Mechanic
总结:正则 + Markdown = 自动化利器
| 简单替换 | VS Code 正则替换 |
| 批量处理 | Python 脚本 + glob |
| 格式校验 | 自定义规则 + CI 集成 |
| 复杂结构 | 结合 markdown 库解析 AST |
记住:不要试图用正则解析所有 Markdown,但 80% 的重复劳动,它都能帮你干掉!


