正则表达式(Regular Expression)是用于描述字符串模式的文本匹配工具。
1 基础语法
1.1 元字符:
元字符 | 描述 |
---|---|
. | 匹配任何字符(除换行符) |
* | 匹配前一个元素零次或多次 |
+ | 匹配前一个元素一次或多次 |
? | 匹配前一个元素零次或一次 |
^ | 匹配行首 |
$ | 匹配行尾 |
[] | 匹配方括号内的任何一个字符 |
[^] | 不匹配方括号内的任何一个字符 |
() | 创建捕获组,用于提取匹配的子串 |
1.2 字符类别:
字符类别 | 描述 |
---|---|
\d | 匹配数字字符(0-9) |
\D | 不匹配数字字符 |
\w | 匹配字母、数字和下划线字符 |
\W | 不匹配字母、数字和下划线字符 |
\s | 匹配空白字符(空格、制表符、换行符等) |
\S | 不匹配空白字符 |
1.3 量词:
量词 | 描述 |
---|---|
{n} | 匹配前一个元素恰好n次 |
{n,} | 匹配前一个元素至少n次 |
{n,m} | 匹配前一个元素至少n次但不超过m次 |
*? | 非贪婪匹配(匹配前一个元素零次或多次,但尽量少) |
+? | 非贪婪匹配(匹配前一个元素一次或多次,但尽量少) |
?? | 非贪婪匹配(匹配前一个元素零次或一次,但尽量少) |
1.4 预测断言:
- 正向前瞻断言 (Positive Lookahead Assertion):
正向前瞻断言用于查找在当前位置之后满足某个模式的文本,但不包括该模式本身。以下是一个示例,查找包含美元符号的价格值:
正则表达式:(?=\$\d+\.\d{2})
import re
text = "The price is $19.99 for the product."
pattern = r"(?=\$\d+\.\d{2})"
matches = re.findall(pattern, text)
print(matches) # 匹配的是包含美元符号价格的位置
在上面的示例中,正向前瞻断言 (?=\$\d+\.\d{2})
匹配包含美元符号和价格值的位置,但不包括它们本身。
- 负向前瞻断言 (Negative Lookahead Assertion):
负向前瞻断言用于查找在当前位置之后不满足某个模式的文本。以下是一个示例,查找不包含特定单词 “apple” 的句子:
正则表达式:(?!.*apple)
import re
sentences = ["I like bananas and oranges.", "Apples are tasty.", "Do you want an apple?"]
pattern = r"(?!.*apple)"
for sentence in sentences:
if re.match(pattern, sentence):
print(f"Matched: {sentence}")
在上面的示例中,负向前瞻断言 (?!.*apple)
匹配不包含 “apple” 的句子。
- 正向后顾断言 (Positive Lookbehind Assertion):
正向后顾断言用于查找在当前位置之前满足某个模式的文本,但不包括该模式本身。以下是一个示例,查找在 “$” 符号之前的价格值:
正则表达式:(?<=\$)\d+\.\d{2}
import re
text = "The price is $19.99 for the product."
pattern = r"(?<=\$)\d+\.\d{2}"
matches = re.findall(pattern, text)
print(matches) # 匹配的是 "$" 后面的价格值
在上面的示例中,正向后顾断言 (?<=\$)
匹配在 “$” 符号之前的价格值。
- 负向后顾断言 (Negative Lookbehind Assertion):
负向后顾断言用于查找在当前位置之前不满足某个模式的文本。以下是一个示例,查找不包含特定单词 “apple” 的句子:
正则表达式:(?<!apple.*)
import re
sentences = ["I like bananas and apples.", "Oranges are tasty.", "Do you want an apple?"]
pattern = r"(?<!apple.*)"
for sentence in sentences:
if re.match(pattern, sentence):
print(f"Matched: {sentence}")
在上面的示例中,负向后顾断言 (?<!apple.*)
匹配不包含以 “apple” 开头的句子。
- 表格总结:
预测断言 | 描述 |
---|---|
(?=) | 正向前瞻断言(前面必须满足某条件) |
(?!) | 负向前瞻断言(前面不能满足某条件) |
(?<=) | 正向后顾断言(后面必须满足某条件) |
(?<!) | 负向后顾断言(后面不能满足某条件) |
1.5 高级语法和模式:
语法/模式 | 描述 |
---|---|
(?: ) | 非捕获组(不捕获匹配的子串) |
\b | 单词边界(匹配单词的开头或结尾) |
\B | 非单词边界(匹配非单词的位置) |
^$ | 匹配空行 |
(…)\1 | 反向引用(匹配前面捕获组中的内容) |
(?i) | 忽略大小写匹配 |
2 常见应用:
-
电话号码匹配:
匹配格式为 (123) 456-7890 或 123-456-7890 的电话号码。
正则表达式:
**\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})**
import re phone_number = "123-456-7890" pattern = r"**\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})**" if re.match(pattern, phone_number): print("Valid phone number") else: print("Invalid phone number")
-
用户名验证:
用户名只包含字母、数字、下划线和连字符,长度为3到20个字符。
正则表达式:
import re username = "my_user123" pattern = r"**^[a-zA-Z0-9_-]{3,20}$**" if re.match(pattern, username): print("Valid username") else: print("Invalid username")
-
密码强度验证:
密码必须包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符,并且长度为8到16个字符。
正则表达式:
**^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@#$%^&+=*!])[A-Za-z\d@#$%^&+=*!]{8,16}$**
import re password = "StrongP@ss1" pattern = r"**^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@#$%^&+=*!])[A-Za-z\d@#$%^&+=*!]{8,16}$**" if re.match(pattern, password): print("Strong password") else: print("Weak password")
-
邮政编码匹配:
匹配美国的邮政编码,可以是5位数字或9位数字,可包含连字符。
正则表达式:
**\d{5}(?:-\d{4})?$**
import re zip_code = "12345-6789" pattern = r"**\d{5}(?:-\d{4})?$**" if re.match(pattern, zip_code): print("Valid ZIP code") else: print("Invalid ZIP code")
3 学习工具
- Regex101 可用于在线测试练习
- Road To Coding 正则表达式总结网站