科普:通配符表达式(Wildcard)与正则表达式(Regular Expression)
通配符表达式(Wildcard)和正则表达式(Regular Expression,简称 Regex)都用于模式匹配(根据规则查找/匹配字符串),但二者在设计目标、语法复杂度和应用场景上存在本质区别。
- 通配符:“平民工具”,简单直观,解决日常基础匹配需求(尤其是文件搜索)。
- 正则表达式:“专业利器”,功能强大,解决复杂、精准的字符串处理需求(开发、数据分析等)。
一、区别:设计目标与复杂度
维度 | 通配符表达式(Wildcard) | 正则表达式(Regex) |
---|---|---|
设计定位 | 轻量级、直观,用于快速匹配文件名/简单字符串 | 强大、灵活的“匹配语言”,处理复杂、精准的字符串需求 |
语法复杂度 | 极简,仅包含2-3个核心符号,易上手 | 复杂,包含大量元字符、量词、分组等,需系统学习 |
匹配能力 | 基础匹配(模糊匹配、前缀/后缀匹配) | 精准匹配、逻辑匹配、捕获提取、替换等高级功能 |
常见应用场景 | 操作系统文件搜索(如 Windows dir 、Linux ls ) | 代码验证(手机号/邮箱)、日志分析、文本处理、爬虫 |
二、语法对比
1. 通配符表达式:仅2个核心符号
通配符的语法极度简化,核心只有 *
和 ?
两个符号,部分场景会扩展 []
(字符集),但无其他复杂规则。
符号 | 含义 | 示例 | 匹配结果(以文件名为例) |
---|---|---|---|
* | 匹配任意长度的任意字符(包括0个) | doc*.txt | doc.txt 、doc123.txt 、document.txt |
? | 匹配1个任意字符(必须有1个) | file?.pdf | file1.pdf 、fileA.pdf |
[] | 匹配括号内的任意1个字符(可选扩展) | img[0-9].jpg | img0.jpg 、img5.jpg |
[!] | 匹配不在括号内的任意1个字符(扩展) | file[!a-z].txt | file1.txt 、file@.txt (排除小写字母) |
2. 正则表达式:核心符号体系
正则表达式的语法丰富,涵盖“字符匹配”“数量控制”“位置定位”“逻辑分组”等维度,以下是最常用的核心符号:
类别 | 符号/语法 | 含义 | 示例 | 匹配结果 |
---|---|---|---|---|
字符匹配 | . | 匹配任意1个字符(默认不含换行 \n ) | a.b | a1b 、a@b 、a b |
\d | 匹配1个数字(等价于 [0-9] ) | num\d{3} | num123 、num456 | |
\w | 匹配1个字母/数字/下划线([a-zA-Z0-9_] ) | user\w | user1 、userA 、user_ | |
[] | 匹配括号内任意1个字符 | [a-z0-9] | a 、5 、z | |
数量控制 | * | 前面元素出现0次或多次(贪婪匹配) | a*b | b 、ab 、aaab |
+ | 前面元素出现1次或多次 | a+b | ab 、aaab (不匹配 b ) | |
? | 前面元素出现0次或1次;或开启非贪婪匹配 | a?b | b 、ab (不匹配 aab ) | |
{n,m} | 前面元素出现n到m次 | a{2,3}b | aab 、aaab | |
位置定位 | ^ | 匹配字符串开头 | ^Hello | 匹配以 Hello 开头的字符串(如 Hello World ) |
$ | 匹配字符串结尾 | World$ | 匹配以 World 结尾的字符串(如 Hello World ) | |
逻辑分组 | () | 分组(将部分表达式视为整体) | (ab)+ | ab 、abab |
| | 逻辑“或” | a|b | a 或 b |
三、举例说明
通过同一需求的不同实现,直观感受二者的区别:
需求1:匹配“以 .txt
结尾,前面有任意内容”的文件名
- 通配符:
*.txt
(极其简单,1秒上手) - 正则表达式:
^.*\.txt$
(需考虑:^
开头、$
结尾、\.
转义.
、.*
匹配任意内容)
需求2:匹配“以 img
开头,中间是2个数字,以 .jpg
结尾”的文件名
- 通配符:
img??.jpg
(用两个?
匹配2个数字,但无法限制“必须是数字”,可能匹配imgAB.jpg
) - 正则表达式:
^img\d{2}\.jpg$
(精准限制中间是2个数字,仅匹配img01.jpg
、img99.jpg
等)
需求3:匹配“11位手机号(以13/15/18开头)”
- 通配符:无法实现(通配符无“逻辑或”和“精准数量+字符类型”的控制能力)
- 正则表达式:
^1[358]\d{9}$
(精准匹配,无误差)
四、应用场景划分
何时用通配符?
- 日常文件搜索:如在 Windows 资源管理器搜索“所有
.docx
文件”(*.docx
)、“名称为report_202?
的文件”(report_202?
)。 - 简单字符串模糊匹配:如在文本编辑器中快速查找“以
log_
开头的单词”(log_*
)。 - 核心诉求:快、简单、无需精准控制字符类型。
何时用正则表达式?
- 数据验证:如代码中验证用户输入的邮箱(
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+$
)、身份证号。 - 日志分析:如从海量日志中提取“2024年的错误日志”(
^2024-\d{2}-\d{2} .* ERROR .*$
)。 - 文本处理:如批量替换“所有手机号中间4位为
****
”((\d{3})\d{4}(\d{4})
替换为$1****$2
)。 - 爬虫数据提取:如从HTML中提取所有
<a>
标签的链接(<a href="(.*?)">
)。 - 核心诉求:精准、复杂逻辑、提取/替换等高级操作。
常见误区
- 符号含义混淆:通配符的
*
和正则的*
都表示“任意长度”,但正则的*
是“修饰前序元素”(如a*
表示“a的0次或多次”),而通配符的*
是“独立匹配任意内容”。 - 转义规则不同:通配符中
.
就是字面意义的“点”(如*.txt
中的.
匹配文件名中的.
);但正则中.
是“任意字符”,需用\.
表示字面意义的“点”(如\.txt
匹配.txt
)。 - 匹配范围默认不同:通配符默认匹配“整个字符串/文件名”;正则默认匹配“字符串中任意符合规则的子串”,需用
^
和$
限制为“整个字符串匹配”。
附一:正则表达式(Regex)简介
正则表达式(Regex)是处理文本匹配、提取、替换的强大工具,不同场景下有大量高频使用的表达式。以下按 基础语法、常见数据提取、格式校验、文本处理 四大类整理了最常用的正则表达式,并附带解析和示例,方便直接复用。
基础语法:核心元字符与量词(必掌握)
这类是构建复杂正则的“积木”,前面对话中提到的 \s+
/\S+
也属于此类。
正则表达式 | 含义说明 | 示例匹配 |
---|---|---|
. | 匹配任意单个字符(除换行符 \n ) | a.c 匹配 abc 、a1c 、a@c |
\d | 匹配单个数字(0-9),等价于 [0-9] | \d{3} 匹配 123 、456 |
\D | 匹配非数字字符,等价于 [^0-9] | \D+ 匹配 abc 、@#$ |
\w | 匹配字母、数字、下划线,等价于 [a-zA-Z0-9_] | \w+ 匹配 user123 、name_456 |
\W | 匹配非字母/数字/下划线,如 @ 、! 、空格 | \W 匹配 @ 、 (空格) |
\s | 匹配空白字符(空格、制表符 \t 、换行符 \n 等) | a\sb 匹配 a b 、a\tb |
\S | 匹配非空白字符(与 \s 相反) | \S+ 匹配 IP10.0.0.1 、GET |
* | 量词:匹配前面元素 0次或多次(贪婪匹配) | ab* 匹配 a 、ab 、abb |
+ | 量词:匹配前面元素 1次或多次 | ab+ 匹配 ab 、abb (不匹配 a ) |
? | 量词:匹配前面元素 0次或1次(可选);或用于非贪婪匹配 | ab? 匹配 a 、ab ;a.*?b 匹配 aab 中的 aab (而非贪婪的 aab...b ) |
{n} | 量词:匹配前面元素 恰好n次 | \d{4} 匹配 2024 (4位数字) |
{n,} | 量词:匹配前面元素 至少n次 | \d{2,} 匹配 12 、345 、6789 |
{n,m} | 量词:匹配前面元素 n到m次 | \d{3,5} 匹配 123 、4567 、89012 |
^ | 锚定符:匹配字符串 开头 | ^abc 匹配 abc123 (不匹配 xabc ) |
$ | 锚定符:匹配字符串 结尾 | 123$ 匹配 abc123 (不匹配 123x ) |
[] | 字符集:匹配括号内任意 单个 字符 | [a-z0-9] 匹配小写字母或数字 |
[^] | 否定字符集:匹配括号外任意 单个 字符 | [^a-z] 匹配非小写字母(如大写、数字、符号) |
() | 捕获组:提取括号内的匹配内容(核心用于“提取”) | (\d{4})-(\d{2}) 可分别捕获年、月 |
` | ` | 逻辑“或”:匹配左边或右边的表达式 |
常见数据提取:从文本中抓关键信息
这类正则用于从日志、网页、文档等非结构化文本中提取结构化数据(如IP、日期、URL等)。
1. 提取IP地址(IPv4)
\b(?:\d{1,3}\.){3}\d{1,3}\b
- 解析:
\b
:单词边界(避免匹配192.168.1.1234
这类无效IP);(?:\d{1,3}\.){3}
:非捕获组(不提取),匹配“1-3位数字+点”3次(如192.168.1.
);\d{1,3}
:匹配最后一段数字。
- 示例:从
Log: 10.0.0.1 accessed 192.168.1.254
中提取10.0.0.1
、192.168.1.254
。
2. 提取URL(含http/https)
https?://[^\s"'<>]+
- 解析:
https?
:匹配http
或https
(s
可选);://
:固定分隔符;[^\s"'<>]+
:匹配非空白、非引号、非尖括号的所有字符(避免URL被截断)。
- 示例:从
Visit https://www.example.com/path?query=1 "test"
中提取https://www.example.com/path?query=1
。
3. 提取日期时间(常见格式)
格式1:年-月-日 时:分:秒(如 2024-05-20 14:30:00)
\b\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\b
格式2:日/月/年 时:分(如 20/05/2024 14:30)
\b\d{2}/\d{2}/\d{4}\s\d{2}:\d{2}\b
4. 提取邮箱地址
\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b
- 解析:
- 用户名:
[a-zA-Z0-9._%+-]+
(允许字母、数字、常见符号); - 域名:
[a-zA-Z0-9.-]+
(如example
、mail.qq
); - 顶级域名:
\.[a-zA-Z]{2,}
(如.com
、.org.cn
,至少2个字母)。
- 用户名:
- 示例:匹配
user.name+tag@example.co.uk
、123_abc@qq.com
。
5. 提取HTML中的图片URL(<img src="xxx">
)
<img\s+src=["']([^"']+)["']
- 解析:
<img\s+
:匹配<img
标签及后续空格;src=["']
:匹配src="
或src='
(兼容单/双引号);([^"']+)
:捕获引号内的URL(非引号字符)。
- 示例:从
<img src='https://img.com/pic.jpg' alt="pic">
中提取https://img.com/pic.jpg
。
格式校验:验证数据是否符合规则
这类正则用于“判断”文本是否满足特定格式(如手机号、身份证号、密码强度等),通常结合 ^
和 $
锚定整个字符串。
1. 校验中国大陆手机号(11位,以13/14/15/16/17/18/19开头)
^1[3-9]\d{9}$
- 解析:
^1
开头,第二位是3-9,后面跟9位数字,以数字结尾。
2. 校验中国大陆身份证号(18位,最后一位可能是X)
^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$
- 解析:包含地区码(6位)、出生年月日(8位,支持19/20/21世纪)、顺序码(3位)、校验码(1位,数字或X)。
3. 校验密码强度(至少8位,含大小写字母、数字、特殊符号中3种)
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*])|(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*])|(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$
- 解析:
(?=.*x)
是“正向预查”,确保包含x;上述表达式覆盖“大小写+数字”“大小写+符号”“小写+数字+符号”“大写+数字+符号”4种组合,且长度≥8。
4. 校验邮箱格式(比“提取”更严格,确保整体合规)
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
- 注意:与“提取邮箱”的表达式一致,但必须结合
^
和$
锚定(提取时用\b
边界即可)。
5. 校验URL格式(含http/https,支持域名/IP)
^https?:\/\/(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}|(?:\d{1,3}\.){3}\d{1,3}(?::\d{1,5})?(?:\/[^\s]*)?$
- 支持:
https://example.com
、http://192.168.1.1:8080/path
。
文本处理:替换、清理、分割文本
这类正则用于批量处理文本(如去空格、替换表情、提取纯文字等)。
1. 匹配并删除所有空白字符(空格、制表符、换行符)
\s+
- 用法:将匹配结果替换为空字符串(如
replace(/\s+/g, "")
)。 - 示例:
" Hello \n World "
→ 替换后为"HelloWorld"
。
2. 匹配中文(含简体、繁体,不含标点)
[\u4e00-\u9fa5]
- 用法:提取中文(匹配所有结果)或过滤中文(替换为空)。
- 示例:从
Hello 你好!World 世界
中提取你好世界
。
3. 匹配所有Emoji表情(覆盖大部分常用表情)
[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F900}-\u{1F9FF}]|[\u{1F1E0}-\u{1F1FF}]
- 用法:替换为空以清理表情(注意:部分语言需开启Unicode修饰符
u
)。
4. 匹配HTML标签(用于去除HTML格式)
<[^>]+>
- 解析:匹配
<
开头、>
结尾的所有字符(即HTML标签)。 - 示例:从
<p>Hello <b>World</b></p>
中匹配<p>
、<b>
、</b>
、</p>
,替换后为"Hello World"
。
附二:正则表达式在中文中的应用
在中文文本中使用正则表达式,核心是通过 Unicode 编码范围定位中文字符,并结合中文特有的标点、语法规则设计匹配模式。以下是具体场景和示例,涵盖提取、验证、替换、过滤等常见操作:
基础:匹配中文字符的核心正则
中文(简体为主)的 Unicode 核心范围是 \u4e00-\u9fa5
,这是所有中文正则的基础。
# 匹配单个中文字符
[\u4e00-\u9fa5]# 匹配多个连续中文字符(1个或多个)
[\u4e00-\u9fa5]+
常见场景与示例
1. 提取中文内容(过滤英文、数字、符号)
需求:从混合文本中提取纯中文片段(不含英文、数字、特殊符号)。
文本:"Hello 你好!2024年,我想去北京天安门。abc123"
正则:[\u4e00-\u9fa5]+
匹配结果:["你好", "年", "我想去北京天安门"]
Python 实现:
import retext = "Hello 你好!2024年,我想去北京天安门。abc123"
chinese = re.findall(r'[\u4e00-\u9fa5]+', text)
print(chinese) # 输出:['你好', '年', '我想去北京天安门']
2. 验证中文姓名(含普通姓名和复姓)
需求:验证输入是否为合法中文姓名(2-4个汉字,支持复姓如“欧阳”“司马·相如”)。
正则:^[\u4e00-\u9fa5]{2,4}$|^[\u4e00-\u9fa5]+\·[\u4e00-\u9fa5]+$
- 解析:
^[\u4e00-\u9fa5]{2,4}$
:匹配2-4个汉字的普通姓名(如“张三”“李四光”)。^[\u4e00-\u9fa5]+\·[\u4e00-\u9fa5]+$
:匹配带“·”的复姓(如“司马·相如”“欧阳·锋”)。
匹配示例:
✅ 合法:"张三"
、"诸葛亮"
、"上官·婉儿"
❌ 非法:"张"
(长度不足)、"李123"
(含数字)、"Ouyang锋"
(含英文)
3. 提取中文句子(含中文标点)
需求:从文本中提取完整的中文句子(包含中文标点,如逗号、句号、感叹号等)。
文本:"今天天气不错,适合出游!你准备去哪里?我想去爬山。"
正则:[^,。!?]+[,。!?]
- 解析:
[^,。!?]+
:匹配“非中文标点”的内容(即句子主体,含中文和空格)。[,。!?]
:匹配结尾的中文标点(逗号、句号、感叹号、问号)。
匹配结果:["今天天气不错,", "适合出游!", "你准备去哪里?", "我想去爬山。"]
4. 替换中文敏感词(内容过滤)
需求:将文本中的敏感词(如“垃圾”“混蛋”)替换为“***”。
文本:"这种行为太垃圾了,简直是混蛋!"
正则:(垃圾|混蛋)
替换结果:"这种行为太***了,简直是***!"
JavaScript 实现:
const text = "这种行为太垃圾了,简直是混蛋!";
const filtered = text.replace(/(垃圾|混蛋)/g, "***");
console.log(filtered); // 输出:"这种行为太***了,简直是***!"
5. 匹配中文地址(含省市区街道信息)
需求:提取地址中的“省/市/区”层级信息(简化版)。
文本:"浙江省杭州市西湖区西湖街道123号"
正则:([\u4e00-\u9fa5]+省)?([\u4e00-\u9fa5]+市)?([\u4e00-\u9fa5]+区)?
- 解析:
([\u4e00-\u9fa5]+省)?
:可选的“省”级(如“浙江省”)。([\u4e00-\u9fa5]+市)?
:可选的“市”级(如“杭州市”)。([\u4e00-\u9fa5]+区)?
:可选的“区”级(如“西湖区”)。
匹配结果(分组提取):
["浙江省", "杭州市", "西湖区"]
6. 过滤中文中的英文和数字
需求:保留文本中的中文和中文标点,删除所有英文、数字和英文符号。
文本:"Hello 2024!这是一个test,测试文本123。"
正则:[^\u4e00-\u9fa5,。!?、;:“”‘’\s]
- 解析:
[^...]
表示“排除这些字符”,保留中文、中文标点和空格。
替换结果:" !这是一个,测试文本。"
中文中注意事项
-
中文标点 vs 英文标点:
中文标点(,。!?“”
)与英文标点(, . ! ? ""
)编码不同,正则中需严格区分。例如匹配中文句号用。
而非.
(.
在正则中是“任意字符”)。 -
扩展中文范围:
若需处理生僻字或繁体,可扩展 Unicode 范围,例如:
[\u4e00-\u9fa5\u3400-\u4db5\u20000-\u2a6d6]
(包含扩展汉字)。 -
性能优化:
大量中文文本匹配时,避免过度复杂的正则(如多层嵌套),优先使用工具的 Unicode 优化模式(如 Python 的re.UNICODE
标志,默认开启)。