在 Markdown 文档中,我们经常会使用 #
来标记标签(tag)。例如,#todo
或 #feature
都可以作为标记嵌入文本中。然而,在 Markdown 中还存在另一种情况:代码块。代码块通常由单个或连续三个反引号(```)包裹,并且代码块内部可能会出现类似 #ff0000
这样的颜色值。如果不加以区分,就会把这些颜色值也识别为标签。
此外,为了避免误判,转义的反引号(\`)也不应被当作真正的分界符。为此,我们需要设计一个既能排除转义反引号,又能将连续的三个反引号作为一个整体处理的正则表达式。
挑战与需求
- 处理代码块边界:Markdown 支持用单个反引号表示行内代码、用三个反引号表示多行代码块。正则表达式需要区分这两种情况,确保在代码块中的
#
不会被误认为标签前缀。
- 转义字符的处理:例如 \` 这样的转义反引号不应计入反引号的配对判断中。
- Tag 匹配规则:标签由
#
开头,后跟 1 至 32 个 Unicode 字母、数字或下划线,且必须在正确的边界下出现。
正则表达式解决方案
经过多次改进,我们最终得到了下面这个正则表达式:
(?=(?:(?:[^`]|\\`)*(?<!\\)(?<delim>```|`)(?:[^`]|\\`)*(?<!\\)(\k<delim>))*(?:[^`]|\\`)*$)(?<=(?:^|[^\\])#)[\p{L}_\p{N}]{1,32}(?=[^\p{L}\p{N}_]|$)
让我们逐步解析这条表达式的关键部分:
1. 保证反引号成对出现
表达式的开头部分使用了复杂的正向前瞻:
(?=(?:(?:[^`]|\\`)*(?<!\\)(?<delim>```|`)(?:[^`]|\\`)*(?<!\\)(\k<delim>))*(?:[^`]|\\`)*$)
- 核心思想:通过匹配一系列非反引号或转义反引号的字符,再加上捕获组
(?<delim>```|
)`,我们捕获了第一次出现的“分界符”——它可能是单个反引号,也可能是连续三个反引号。
- 反向引用:利用
\k<delim>
,确保后续匹配的分界符与前面捕获到的完全一致。这样,无论遇到的是行内代码还是代码块,都只视作一个整体。
- 成对匹配:整个正向前瞻确保了目标区域内所有未转义的反引号都是成对出现的,避免了误将代码块内部的内容当作标签判断依据。
2. 确保标签前缀正确
接下来的部分:
(?<=(?:^|[^\\])#)
- 作用:这个正向后查断言确保了标签必须由一个
#
开头,而这个 #
不能被反斜杠转义(即不应为 \#
)。
3. 匹配 Tag 内容
标签的主体部分由下面这段完成:
[\p{L}_\p{N}]{1,32}(?=[^\p{L}\p{N}_]|$)
- 匹配范围:这里
[\\p{L}_\\p{N}]
表示 Unicode 字母、数字以及下划线。{1,32}
限定了标签的长度为 1 至 32 个字符。
- 边界条件:紧跟的正向查找断言
(?=[^\p{L}\p{N}_]|$)
确保标签后面紧跟的是非单词字符或已经到达字符串末尾,防止匹配到类似 #todoing
这种不完整的标签。
小结
这条正则表达式综合了多种复杂情况,既能处理 Markdown 中单反引号和三反引号的代码块,又能排除转义反引号的干扰,同时严格匹配标签格式。对于开发者来说,这样的表达式在解析 Markdown 文档、提取标签或进行格式化处理时非常有用。
当然,正则表达式的可读性和维护性是一个平衡点。虽然这条表达式在处理边界情况时表现出色,但在实际应用中可能还需要根据具体场景做出微调。希望这篇文章能为你在 Markdown 文档解析方面提供一些灵感和帮助。
在2024年,跟往年一样,没有计划,纯粹跟着兴趣读,我一共读完了37本书,其中有两本书是重读的。
- 毛泽东私人医生回忆录
- 辉煌信标-美国灯塔史
- 倭寇 海上历史
- 汉文与东亚世界
- 老滇缅路
- 天生幸存者
- 一个美国女孩在中国
- 红色赌盘
- 暗淡蓝点
- 接触
- 蒋介石的美国顾问-欧文拉铁摩尔回忆录
- 宇宙 -- 从大爆炸到毁灭
- 地图三千年
- 世界上的鸟儿(套书共5本)
- 人间相亲故事
- 三星堆文化大猜想
- 回到石器时代
- 何伟的中国纪实
- 寻路中国
- 抱歉,我动了你的脑子
- 别逗了费曼先生 (重读)
- 费曼手札—不休止的鼓声
- 当呼吸化为空气(重读)
- 解码40亿年生命史
- 140亿年宇宙演化全史
- 掌控习惯
- 超级生物探寻指南
- 草民
- 写在基因里的食谱
- 远去的胜利 - 德国前线将领二战回忆录
- 长乐路
- 范妮 希尔
不算很好的成绩,也不算很坏。希望我的2025能多读几本书!
我的生活态度是,早上起床想一想,我有可能活不到今天晚上,晚上上床想一想,我有可能活不到明天早上。-- 德图里子爵(1776-1854),法国贵族
乔布斯 我热爱消费者市场,讨厌企业市场。我们推出了一种产品,告诉每个人,大家自己决定要不要买,这很简单。但是,企业市场不是这样,使用产品的人自己做不了主,而做主的人不使用产品。
我们拥有的机会并没有我们以为的那么多。太多事情你以为还有的是机会去做,其实已经没有了或者几乎没有了。
米福根 女儿回家的周末,与我一起和外公外婆分享我们的平常生活:去生物博士开的二手店买旧衣服,去南瓜节买当地产当天收的蔬菜,去老厂房看本市家禽俱乐部为下个周末布展。每一个场景,都是大家在热忱地做自己喜欢的事情,这应该就是传说中的安居乐业。
米福根 恋爱的智慧,不是试图改变对方,而是扪心自问,能否与这样的缺失共处…然后为自己做一个决定。
We Don’t See Things As They Are, We See Them As We Are.
我们所见的,不是事物的本来面目,而是我们自身的投射。
人们对事物的理解和看法往往并不取决于事物本身,而是受到自身的经验、情绪、偏见等因素的影响。因此,我们“看到的”实际上是我们自身的投射,是我们内在的世界映射到外在事物上的样子。
是什么让我忘记了时间的流逝?“心流”指的是你因为全神贯注地投入手头的工作,从而忘记了周边世界的存在的一种精神状态。当运动员和表演者处于“这个区域”时,他们所经历的就是这种快乐和巅峰表现的交融。你从事的工作或多或少会让你感到愉悦,否则你几乎不可能体验到心流。
小青 昨天和朋友交流学意大利语的艰难经历,我们共同的体会就是,每天都要学,一天都不能断。断断续续等于浪费时间。
我们现在已经不再费功夫检测性格特征是否含有遗传成分,因为我们根本找不到不受基因影响的成分。

这篇博文是(2011年)从新浪博客迁过来的。新浪的编辑还有点人味,这篇没有彻底给删掉,给搁回收站了。转到这儿,看看点点是不是开明一点。
这本书是阮一峰在他的2010年终总结博客里推荐的。
读这本书之前,我对吴法宪的了解仅限于以往看到听到的一些官方说法,四人帮的帮凶什么的。对这本书一开始也没大重视,一个大老粗,文字能好到哪里去呢?不过既然阮一峰会推荐,这书肯定有可取之处。
本着看闲书的态度找到这本书的电子版,扔到kindle里,准备有一搭没一搭的看。
这书篇幅挺大,有八十余万字。一周前开了头,看了十来页,我就知道这本书我一定会全部读完了。
…more
本文最初发表在今天已经死掉的点点博客。
我的第一个移动读书设备是黑莓8310。在那小小的屏幕上我读完了厚厚的一本《代码大全》。
后来买了吹的牛哄哄的号称读PDF多好多好的歌美S6000。屁,操作之慢让我忍不住想起我那只扔在一边的N73手机,阅读时间短不说,电量指示还超不准。读着读着,不定啥时候突然就没电了。
扔一边了,真可惜了8个G的容量。
然后就买了kindle3。刷了多看系统,这次看PDF真的爽了。更爽的是待机时间,充一次电能看两个礼拜。老早就听说这玩意屏不结实,所以入手大半年来,一直小心着小心着,生怕它那脆弱的小屏坏掉。然而,前几天悲剧还是发生了:要和儿子出去玩,我把kindle装包里,包跨在我胳膊上。我为了帮他找鞋子就趴在地上往沙发底下瞧,鞋子是找到了,可起身才发现包在我膝盖底下。啊呀呀,叫也没用,kindle3屏幕果然坏掉。在等待换屏的日子里,顺理成章儿子的iPAD成了暂时的替代。
原来iPAD也是看书利器。虽然最初沉甸甸地,好象有点受不了。可连着带了几天之后发现竟然有些适应了。反应敏捷,操控一流,彩色,大屏,十几小时的阅读时间,除了一点点反光让人稍微不爽,在习惯了iPAD的重量之后,我竟然有些爱不释手了。
要不要就此让那个kindle3成为往事?嗯,这事儿我看行。
2011/06/20