Regular Expressions Cheatsheet 正则表达式小抄
假如有如下csv表格
order_id, fee_amount <br>
1, 1 <br>
2, 2 <br>
...
希望能够转换成下面的SQL UDPATE语句
UPDATE xx_tab SET fee_amount = 666 WHERE order_id = 1; <br>
UPDATE xx_tab SET fee_amount = 666 WHERE order_id = 2; <br>
...
可以使用正则在vscode替换、或写脚本快速完成
import re
csv_data = """order_id, fee_amount
1, 1
2, 2
3, 3"""
pattern = r"(\d+),\s*(\d+)"
replacement = r"UPDATE xx_tab SET fee_amount = 666 WHERE order_id = \1;"
sql_output = re.sub(pattern, replacement, csv_data)
print(sql_output)
捕获vs非捕获 Capturing VS non-capturing
特性 | 捕获组 (…) | 非捕获组 (?:…) |
---|---|---|
定义方式 | 使用圆括号,如 (abc) | 在圆括号内加入 ?: ,如 (?:abc) |
匹配功能 | 分组并保存匹配结果,可用于后续引用 | 仅分组,不保存匹配结果 |
组编号 | 自动分配编号(\1、\2 等),保存于捕获组列表中 | 不参与组编号,不会影响捕获组的编号 |
应用场景 | 当需要提取匹配内容或者在正则中使用反向引用时使用 | 仅需要逻辑分组,不需要提取数据时使用 |
捕获组用于存储匹配的子模式,以便后续引用。可以通过索引(位置捕获)或名称(命名捕获)访问。
位置捕获(索引访问)
import re
pattern = r'(\d{4})-(\d{2})-(\d{2})'
text = "2025-02-26"
match = re.match(pattern, text)
if match:
print(match.group(1)) # 输出 2025
print(match.group(2)) # 输出 02
print(match.group(3)) # 输出 26
命名捕获(名称访问)
命名捕获组允许使用有意义的名称代替编号,提高可读性和可维护性。
import re
pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
text = "2025-02-26"
match = re.match(pattern, text)
if match:
print(match.group("year")) # 输出 2025
print(match.group("month")) # 输出 02
print(match.group("day")) # 输出 26
反向引用(Backreferences)
反向引用用于在正则表达式内部引用先前匹配的捕获组。
- 位置捕获使用
\n
进行反向引用(n
是捕获组编号)。 - 命名捕获使用
(?P=name)
进行反向引用。
示例:匹配重复的单词
import re
pattern = r'\b(\w+) \1\b'
text = "hello hello world"
match = re.search(pattern, text)
if match:
print(match.group(1)) # 输出 hello
使用命名捕获的版本:
import re
pattern = r'\b(?P<word>\w+) (?P=word)\b'
text = "hello hello world"
match = re.search(pattern, text)
if match:
print(match.group("word")) # 输出 hello
案例分析
示例编号 | 示例文本 | 正则表达式 | 匹配结果 | 说明 |
---|---|---|---|---|
1 | "hello hello" | (\w+)\s+\1 | 匹配 "hello hello" | 捕获一个单词,然后要求后面出现相同的单词。 |
2 | "<div>Content</div>" | <(\w+)>.*?</\1> | 匹配整个 <div>Content</div> | 捕获 HTML 标签名(如 div),并确保结束标签与开始标签一致。 |
3 | "aba" | ^(\w).\1$ | 匹配 "aba" | 三字符字符串,第一个和第三个字符必须相同。 |
4 | "abcabc" | ^(\w+)\1+$ | 匹配 "abcabc" | 捕获一个子串(如 "abc"),并要求整个字符串由该子串重复构成。 |
5 | "test test" | (?P<word>\w+)\s+(?P=word) | 匹配 "test test" | 使用命名捕获组,将匹配的单词命名为 word,然后通过 (?P=word) 引用。 |
零宽断言
零宽断言是正则表达式中的一种特殊工具,用于检测目标位置前后是否符合指定的模式,但不会捕获(capture)这些字符。根据检测方向及要求的不同,零宽断言分为以下四种类型:
断言类型 | 语法 | 说明 | 示例说明 |
---|---|---|---|
正向先行断言 | (?=pattern) | 匹配当前位置后面必须跟随指定模式(pattern)的情况 | \w+(?=\d) :匹配一个单词,当且仅当其后紧跟数字时匹配成功 |
负向先行断言 | (?!pattern) | 匹配当前位置后面不能跟随指定模式(pattern)的情况 | foo(?!bar) :匹配“foo”,但要求其后不能跟“bar” |
正向后顾断言 | (?<=pattern) | 匹配当前位置前面必须以指定模式(pattern)结束的情况 | (?<=\$)\d+ :匹配一串数字,要求其前面紧跟一个美元符号 $ |
负向后顾断言 | (?<!pattern) | 匹配当前位置前面不能以指定模式(pattern)结束的情况 | (?<!\$)\d+ :匹配一串数字,要求其前面没有美元符号 $ |
贪婪
\ | 说明 | 语法 | 示例 |
---|---|---|---|
贪婪 | 尽可能重复限定词 | x{1,100} | \d{2,6} 捕获 12342222222222 中的123422 |
非贪婪 | 不重复限定词,在数量后后加个问号 | x{1,100}? | \d{2,6}? 捕获 12342222222222 中的 12 |
RegexFlag
正则表达式 | 描述 | 反义表达式 | 反义描述 |
---|---|---|---|
\w | 匹配字母、数字、下划线([0-9a-zA-Z_] ) | \W | 匹配非字母、非数字、非下划线 |
\s | 匹配空白字符(空格、\t 、\n 、\r 等) | \S | 匹配非空白字符 |
\d | 匹配数字(0-9 ) | \D | 匹配非数字 |
\b | 匹配单词边界(单词开头或结尾) | \B | 匹配非单词边界 |
[x] | 匹配字符 x | [^x] | 匹配除 x 以外的字符 |
\n | 匹配换行符 | —— | —— |
\g<name> 或 \g<number> | 引用命名或编号的捕获组 | —— | —— |
^ | 匹配行开头 | —— | —— |
$ | 匹配行结尾 | —— | —— |
(?i) | 启用大小写不敏感匹配 | —— | —— |
/a(?i)a/g | 行内大小写不敏感匹配(匹配 aA 、aa ,但不匹配 ab ) | —— | —— |
\L(\w) | 转换捕获的字符为小写 | \U(\w) | 转换捕获的字符为大写 |
与或非
正则中只有或,与和非可以用零宽断言(前瞻、负前瞻)来实现。
操作 | 方法 | 主要技巧 | 适用场景 |
---|---|---|---|
与(AND) | (?=.*A)(?=.*B).* | Lookahead(前瞻) | 需要匹配多个条件同时存在 |
或(OR) | **` | `(管道符)** | `A |
非(NOT) | (?!A).* 或 [^...] | 负向前瞻 (?!A) 、排除字符 [^...] | 需要排除某些模式 |
vscode 替换案例
不替换第一个捕获的值
- 搜索
(.*)
- 使用
$1
替换
保留前后的捕获值
- 搜索
(Manager)(\s)(\w.*Manager,)
- 使用
$1 handler.$3
替换