正则表达式用法
正则表达式(Regular Expression,简称 Regex)是一种强大的文本处理工具,用于匹配、查找、替换和提取字符串中的特定模式。它广泛应用于编程、数据清洗、日志分析以及 Markdown 解析等场景。
基础语法元素
正则表达式由普通字符和元字符组成。以下是核心语法的分类说明:
预定义字符类
| 字符 | 含义 | 等价形式 |
|---|---|---|
. | 匹配除换行符以外的任意字符 | - |
\d | 匹配数字字符 | [0-9] |
\D | 匹配非数字字符 | [^0-9] |
\w | 匹配单词字符(字母、数字、下划线) | [a-zA-Z0-9_] |
\W | 匹配非单词字符 | [^a-zA-Z0-9_] |
\s | 匹配空白字符(空格、Tab、换行等) | [\t\n\x0B\f\r] |
\S | 匹配非空白字符 | [^\t\n\x0B\f\r] |
边界匹配
| 字符 | 含义 |
|---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的结尾 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
量词(重复匹配)
| 字符 | 含义 |
|---|---|
* | 匹配前一个元素 0 次或多次 |
+ | 匹配前一个元素 1 次或多次 |
? | 匹配前一个元素 0 次或 1 次 |
{n} | 匹配前一个元素恰好 n 次 |
{n,} | 匹配前一个元素至少 n 次 |
{n,m} | 匹配前一个元素 n 到 m 次 |
注意:默认情况下,量词是贪婪模式(尽可能多匹配)。在量词后加
?(如*?,+?)可变为非贪婪模式(尽可能少匹配),这在解析嵌套结构(如 HTML/Markdown 标签)时非常重要。
分组与捕获
分组允许将多个字符视为一个整体进行重复匹配,并可以“捕获”匹配到的内容供后续使用。
捕获组(exp)
使用圆括号()包裹的子表达式称为捕获组。正则引擎会记录匹配到的内容,并分配编号。
- 编号规则:从左到右,根据左括号出现的顺序编号,从 1 开始。整个表达式默认为第 0 组。
- 反向引用:在正则表达式内部,可以使用
\1,\2引用前面捕获组匹配到的具体文本。
示例:匹配成对的引号
(['"]).*?\1(['"]):捕获单引号或双引号,存入第 1 组。.*?:非贪婪匹配中间的内容。\1:引用第 1 组捕获的内容,确保结尾引号与开头一致。
命名分组(?P<name>exp)
在 Python 等语言中,可以为分组命名,提高可读性。
- 定义:
(?P<name>pattern) - 引用:
(?P=name)或在替换时使用$name/${name}
示例:匹配 HTML 标签
<(?P<tag>\w+)>(.*?)</(?P=tag)>非捕获组(?:exp)
如果只需要分组功能(如应用量词),但不需要保存匹配结果,使用非捕获组可以节省内存。
- 语法:
(?:pattern) - 特点:不占用分组编号,无法通过
\1或group()获取内容。
应用:解析 Markdown 语法
正则表达式常用于轻量级的 Markdown 到 HTML 转换。以下是常见元素的解析思路:
标题 (Headers)
Markdown 标题以 `` 开头,后跟空格和文本。
- 正则:
^{1,6}\s+(.+)$(需开启多行模式) - 替换为:
<h$1>$2</h$1>$1:捕获 `` 的数量(1-6),决定标题级别。$2:捕获标题文本。
强调 (Emphasis)
粗体 (
text或__text__)- 正则:
(\*\*|__)([^\*\n]+?)\1 - 替换为:
<strong>$2</strong> - 说明:
\1确保结束标记与开始标记一致(都是**或都是__);+?使用非贪婪匹配防止跨行误捕。
- 正则:
斜体 (
*text*或_text_)- 正则:
(\*|_)([^\*\n]+?)\1 - 替换为:
<em>$2</em>
- 正则:
行内代码 (Inline Code)
- 正则:
`([^`\n]+)` - 替换为:
<code>$1</code>
链接与图片 (Links & Images)
链接和图片语法相似,图片多一个前置!。
图片:
!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)$1:Alt 文本$2:图片源地址 (src)$3:可选标题 (title)- 替换为:
<img src="$2" alt="$1" title="$3" />
链接:
\[([^\]]*)\]\(([^)\s]+)\)- 替换为:
<a href="$2">$1</a>
- 替换为:
注意事项
- 转义特殊字符:在匹配
.*+?()[]{}^$\|等元字符时,必须使用\进行转义。 - HTML 转义:在将 Markdown 转换为 HTML 时,务必先对原始文本中的
<>&等字符进行 HTML 实体转义,防止 XSS 注入或标签闭合错误。 - 非贪婪匹配:在处理包含多个相同标记的行内元素(如粗体、链接)时,务必使用非贪婪量词(
*?,+?),否则正则可能会从第一个开始标记一直匹配到最后一个结束标记,导致中间内容被错误吞并。 - 性能考量:复杂的嵌套正则可能导致回溯灾难(ReDoS)。对于复杂的 Markdown 解析(如嵌套列表、表格、块引用),建议使用专门的解析器(如 Marked, Remarkable)而非纯正则。
- 测试工具:编写正则时,推荐使用在线测试工具(如 Regex101, RegExr)实时验证匹配结果和分组捕获情况。
常用语言中的调用示例 (Python)
importre text="Hello World\nThis is bold and this is *italic*."# 替换粗体bold_pattern=r'(\*\*|__)([^\*\n]+?)\1'text=re.sub(bold_pattern,r'<strong>\2</strong>',text)# 替换斜体italic_pattern=r'(\*|_)([^\*\n]+?)\1'text=re.sub(italic_pattern,r'<em>\2</em>',text)# 替换标题header_pattern=r'^{1,6}\s+(.+)$'defreplace_header(match):level=len(match.group(0).split())# 计算 的数量content=match.group(1)returnf'<h{level}>{content}</h{vel}>'text=re.sub(header_pattern,replace_header,text,flags=re.MULTILINE)print(text)