前言
工作中常用的知识是我们应付日常工作的利器,本系列文章将盘点一下工作中常用的知识(那种拿来就能用的)。本文为该系列第一篇:正则表达式。正则表达式的学习需要一定的练习和实践,但一旦掌握,它将成为处理文本数据的有力工具。
1.什么是正则表达式
百度百科:
正则表达式(Regular Expression,简称regex)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。
简单来说就是:正则表达式是一种字符模式,用于在查找过程中匹配指定的字符。
那使用正则表达式能处理哪些工作呢?
- 模式匹配:用于在字符串中查找与特定模式匹配的部分。
- 查找和替换:在文本中查找符合特定模式的字符串,并将其替换为其他字符串。
- 分割和分组:将字符串分割成多个部分,或者将匹配的部分组合在一起。
- 数据提取:从文本中提取符合特定模式的字符串,并可以将其保存到变量中。
- 数据验证:用于验证输入字符串是否符合特定的格式或规则,例如电子邮件地址、电话号码等。
- 自动化脚本:可以与其他编程语言结合使用,自动化处理各种文本任务。
2.基本语法
2.1 元字符
正则表达式的元字符是构建正则表达式模式的基本元素。它们有特殊的含义和用途。以下是一些常见的正则表达式元字符及其描述:
.
(点号):匹配除换行符以外的任意单个字符。^
(脱字符):匹配输入字符串的开始位置。在多行模式下,它还可以匹配每一行的开始。$
(美元符号):匹配输入字符串的结束位置。在多行模式下,它还可以匹配每一行的结束。*
(星号):匹配前面的子表达式零次或多次。+
(加号):匹配前面的子表达式一次或多次。?
(问号):匹配前面的子表达式零次或一次。{n}
:n 是一个非负整数,匹配前面的子表达式恰好 n 次。{n,}
:n 是一个非负整数,匹配前面的子表达式至少 n 次。{n,m}
:m 和 n 均为非负整数,其中 n <= m,匹配前面的子表达式至少 n 次,但不超过 m 次。*?
:表示前面的字符或分组可以出现零次或多次,但尽可能少地匹配。例如,对于字符串 "aaa",正则表达式 "a*?" 会匹配到空字符串,而不是整个 "aaa",因为它会尽可能少地匹配字符 "a"。+?
:表示前面的字符或分组可以出现一次或多次,但尽可能少地匹配。例如,对于字符串 "aaa",正则表达式 "a+?" 会匹配到第一个 "a",而不是整个 "aaa",因为它会尽可能少地匹配字符 "a"。??
:表示前面的字符或分组可以出现零次或一次,但尽可能少地匹配。例如,对于字符串 "a",正则表达式 "a??" 会匹配到空字符串,而不是 "a",因为它会尽可能少地匹配字符 "a"。{n}?
:表示前面的字符或分组恰好出现 n 次,但尽可能少地匹配。这与 {n} 的贪婪匹配相对应,后者会尽可能多地匹配字符。{n,}?
:表示前面的字符或分组至少出现 n 次,但尽可能少地匹配。这与 {n,} 的贪婪匹配相对应,后者会尽可能多地匹配字符。{n,m}?
:表示前面的字符或分组至少出现 n 次,但不超过 m 次,且尽可能少地匹配。这与 {n,m} 的贪婪匹配相对应,后者会尽可能多地匹配字符。\
(反斜杠):用作转义字符,它允许你使用正则表达式的特殊字符作为普通字符。[]
(方括号):定义字符集,匹配方括号中列出的任意一个字符。[^]
:定义否定字符集,匹配不在方括号中列出的任意一个字符。()
(圆括号):定义捕获组,用于捕获匹配的子字符串,以便后续引用。(?:)
:定义非捕获组,用于对一组模式进行分组,但不捕获匹配的文本。(?=...)
:前瞻断言,用于匹配后面跟随指定模式的文本。例如:a(?=,a\b) 它检查a后面是否紧跟着一个逗号、字母 "a" 和一个单词边界。(?!...)
:前瞻断言,用于匹配后面不跟随指定模式的文本。|
(竖线):定义选择操作,匹配竖线左右两边的任意一个模式。\d
:匹配任意数字,等价于 [0-9]。\D
:匹配任意非数字字符,等价于 [^0-9]。\w
:匹配任意单词字符,等价于 [a-zA-Z0-9_]。\W
:匹配任意非单词字符,等价于 [^a-zA-Z0-9_]。\s
:匹配任意空白字符,包括空格、制表符、换页符等。\S
:匹配任意非空白字符。\b
:匹配一个单词边界,即单词字符和非单词字符之间的位置。例如,正则表达式"\bapple\b"将匹配字符串中的单词"apple",而匹配不上 applea\B
:匹配一个非单词边界的位置。
注意:不同的正则表达式引擎可能会有一些细微的语法差异和额外的元字符。上面的列表提供了一些常见的元字符,但并不是详尽无遗的。各位同学有用的可以来这里查!!!
2.2 运算符优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似,相同优先级的从左到右进行运算,不同优先级的运算先高后低。 以下是一些常见正则表达式运算符按照优先级从高到低的顺序:
- 转义符号:
\
是用于转义其他特殊字符的转义符号,它具有最高的优先级。示例:\d
、\
. 等,其中\d
匹配数字,\.
匹配点号。 - 括号: 圆括号
()
用于创建子表达式,具有高于其他运算符的优先级。示例:(abc)+
匹配 "abc" 一次或多次。 - 量词: 量词指定前面的元素可以重复的次数。示例:
a*
匹配零个或多个 "a"。 - 字符类: 字符类使用方括号
[]
表示,用于匹配括号内的任意字符。示例:[aeiou]
匹配任何一个元音字母。 - 断言: 断言是用于检查字符串中特定位置的条件的元素。示例:
^
表示行的开头,$
表示行的结尾。 - 连接: 连接在没有其他运算符的情况下表示字符之间的简单连接。示例:abc 匹配 "abc"。
- 管道: 管道符号
|
表示"或"关系,用于在多个模式之间选择一个。示例:cat|dog
匹配 "cat" 或 "dog"。
2.3 修饰符
正则表达式的修饰符(也称为标记或选项)是用来修改搜索模式的特殊字符或标志。它们可以添加到正则表达式的末尾,以控制匹配的方式和行为,在 vim 中常用。以下是一些常见的正则表达式修饰符及其描述:
g
(全局):表示全局匹配,即在整个字符串中搜索所有匹配项,而不仅仅是第一个匹配项。i
(不区分大小写):表示在匹配时忽略大小写。m
(多行):表示多行模式,在这种模式下,正则表达式可以同时匹配每一行的内容,而不仅仅是整个字符串。s
(单行):修改.特殊字符的行为,使其匹配包括换行符在内的任意字符。默认情况下,.只匹配除换行符之外的任意字符。u
(Unicode):表示在匹配时进行Unicode模式的匹配,可以正确处理四个字节的Unicode字符。y
(粘附):使匹配只能发生在目标字符串的当前位置,确保从给定的位置开始匹配。这在某些情况下可以提高匹配的效率。x
(忽略空白):忽略正则表达式中的空白字符(除非它们被转义或在字符类中),这可以提高正则表达式的可读性。
我们拿 g 举一个简单的例子:假设我们有一个包含多个数字的字符串,我们想要提取出所有的数字。我们可以使用正则表达式和一个包含"g"标志的搜索方法来实现这个目的。
javascript
javascript复制代码
const input = "There are 123 apples and 456 oranges in the basket.";
const regex = /\d+/g; // 匹配一个或多个数字,使用"g"标志进行全局搜索
// 在JavaScript中使用正则表达式的exec方法获取所有匹配项
let matches = [];
let match;
while ((match = regex.exec(input)) !== null) {
matches.push(match[0]); // 将每个匹配项添加到数组中
}
console.log(matches); // 输出: ["123", "456"]
在这个例子中,正则表达式/\d+/g
用于匹配一个或多个数字。由于我们使用了"g
"标志,exec 方法会继续搜索输入字符串,直到找到所有匹配的数字。然后,我们将每个匹配项添加到一个数组中,并最终输出这个数组。
需要注意的是,并非所有的正则表达式引擎都支持所有的修饰符,而且某些修饰符可能在不同的引擎中有不同的行为或名称。因此,在使用正则表达式时,最好查阅相关文档以了解特定引擎对修饰符的支持情况。
此外,修饰符可以单独使用,也可以组合使用,以满足不同的匹配需求。例如,gi
表示既进行全局匹配又忽略大小写,mu
表示既进行多行匹配又进行 Unicode 匹配。组合使用修饰符时,它们的顺序通常不会影响结果,但最好按照一致的顺序书写以提高代码的可读性。
3.常用的正则表达式
3.1 匹配电子邮件地址
javascript
\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b
解析:
\b
表示单词边界。[A-Za-z0-9._%+-]+
匹配由字母、数字和一些特殊字符组成的字符串,至少出现一次。@
匹配 "@" 符号。[A-Za-z0-9.-]+
匹配由字母、数字、点或短横线组成的字符串,至少出现一次。\.
匹配点号(由于点号在正则表达式中是特殊字符,所以需要用反斜杠进行转义)。[A-Za-z]{2,}
匹配至少两个字母的顶级域名。
举例:
- 输入字符串:"Contact us at info@example.com or admin@example.co.uk."
- 匹配结果:"info@example.com", "admin@example.co.uk"
3.2 匹配日期
javascript
\b(?:\d{4}-\d{2}-\d{2}|\d{2}/\d{2}/\d{4}|\d{2}-\d{2}-\d{4}|\d{4}/\d{2}/\d{2})\b
解析:
\b
表示单词边界。(?: ... | ... | ... | ... )
是一个非捕获组,用于匹配多种日期格式中的任意一种。\d{4}-\d{2}-\d{2}
匹配YYYY-MM-DD格式的日期。\d{2}/\d{2}/\d{4}
匹配MM/DD/YYYY格式的日期。\d{2}-\d{2}-\d{4}
匹配MM-DD-YYYY格式的日期(不常见,但为了完整性而包括)。\d{4}/\d{2}/\d{2}
匹配YYYY/MM/DD格式的日期。\b
表示单词边界。
举例:
- 输入字符串:"Today's date is 2023-03-15 or it could be 03/15/2023."
- 匹配结果:"2023-03-15" 和 "03/15/2023"
3.3 匹配 URL
javascript
https?:\/\/(?:[-\w.]|(?:%[\da-fA-F]{2}))+
解析:
这个正则表达式是用于匹配 URL 的,特别是 HTTP 和 HTTPS 协议的 URL:
https?
:http 和 s 是字面字符,分别匹配字符串 "http" 和 "s"。? 表示前面的字符(在这里是 s)可以出现0次或1次。因此,https? 可以匹配 "http" 或 "https"。:\/\/
::
是字面字符,匹配冒号 ":"。\/\/
是两个斜杠字符,用于匹配URL中的 "//"。在正则表达式中,斜杠 / 通常需要被转义(即前面加上反斜杠 \),因为斜杠在很多正则表达式引擎中是一个特殊字符。(?:[-\w.]|(?:%[\da-fA-F]{2}))+
:- 这是一个非捕获组(由
(?: ... )
表示),它允许我们对一组模式进行分组,但不捕获匹配的文本。 +
表示前面的组可以出现一次或多次。[-\w.]
匹配任何单个字符,该字符可以是:-
(连字符)、\w
(匹配任何单词字符,等价于[a-zA-Z0-9_])
、.
(点号)|
是一个选择操作符,它允许我们匹配[-\w.]
或后面括号中的模式。(?:%[\da-fA-F]{2})
是另一个非捕获组,它匹配一个百分号 "%" 后面跟着两个十六进制数字(不区分大小写)。这对应于URL编码中的字符表示。\d
匹配任何数字,[a-fA-F]
匹配任何十六进制字符(不区分大小写)。
- 这是一个非捕获组(由
举例:
- 输入字符串:"Visit www.example.com/page1 or www.anotherexample.net."
- 匹配结果:"www.example.com/page1", "www.anotherexample.net"
3.4 匹配 HTML 中的链接
javascript
<a\s+href="([^"]+)">([^<]+)<\/a>
解析:
<a\s+href="
匹配以 <a 开始,后面跟着一个或多个空白字符和 href=" 的字符串。([^"]+)
是一个捕获组,匹配不包括双引号的任何字符序列,这通常是URL。">
匹配 "> 字符串,表示链接文本的开始。([^<]+)
是另一个捕获组,匹配不包括小于号的任何字符序列,这通常是链接的可见文本。<\/a>
匹配 字符串,表示链接的结束。
举例:
- 输入字符串:
"<a href="https://www.example.com">Visit Example</a>"
- 匹配结果:
- 捕获组 1 得到 URL "www.example.com"
- 捕获组 2 得到链接文本 "Visit Example"。
3.5 匹配 IP 地址
javascript
^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
解析:
^
表示字符串的开始。(?: ... )
是一个非捕获组,用于分组但不捕获匹配的文本。25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?
匹配0到255之间的数字,这是IP地址的每个段的有效范围。\.
匹配点号,由于点号在正则表达式中是特殊字符,所以需要使用反斜杠进行转义。{3}
表示前面的组(即IP地址的前三个段)应该恰好出现三次。$
表示字符串的结束。
举例:
- 输入字符串:"192.168.1.1"
- 匹配结果:"192.168.1.1"
3.6 匹配电话号码(包含区号和分机号)
javascript
^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$
解析:
这个正则表达式是用于匹配中国大陆地区的手机号码的。手机号码在中国通常是以 1 开头的 11 位数字:
^
:表示字符串的开始。(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])
:这是一个捕获组,用于匹配手机号码的前三位数字。这个捕获组包含了多个选择项,用|分隔,表示只要匹配其中一个选择项即可。13[0-9]
:匹配以 13 开头,第二位是 0 到 9 之间的任意数字,即 130-139 之间的号码。14[01456879]
:匹配以 14 开头,第二位是 0、1、4、5、6、8、7、9 中的任意一个数字。这涵盖了 140、141、144、145、146、147、148、149 这些号段。15[0-35-9]
:匹配以 15 开头,第二位是 0 到 3、5 到 9 之间的任意数字。这涵盖了 150、151、152、153、155、156、157、158、159 这些号段。16[2567]
:匹配以 16 开头,第二位是 2、5、6、7 中的任意一个数字。这涵盖了 162、165、166、167 这些号段。17[0-8]
:匹配以 17 开头,第二位是 0 到 8 之间的任意数字。这涵盖了 170 到 178 之间的号码。18[0-9]
:匹配以 18 开头,第二位是 0 到 9 之间的任意数字,即 180-189 之间的号码。19[0-35-9]
:匹配以 19 开头,第二位是 0 到 3、5 到 9 之间的任意数字。这涵盖了 190、191、192、193、195、196、197、198、199 这些号段。
\d{8}
:匹配接下来的8个数字字符(0-9)。\d是数字字符的简写,{8}表示前面的元素(在这里是\d)应该出现8次。$
:表示字符串的结束。
这个正则表达式匹配的是以1开头,第二位是 3、4、5、6、7、8、9 中的任意一个数字,并且总长度为 11 位的手机号码。这个正则表达式涵盖了目前中国大陆地区的大部分手机号码号段,但可能不包括所有新开放的号段或特殊号段。在实际应用中,可能需要根据最新的手机号码分配规则来更新这个正则表达式。
举例:(电话乱写的,别打哈!!!)
- 输入字符串:"18846782278"
- 匹配结果:"18846782278"
3.7 匹配用户名(包含字母、数字、下划线,长度在 6~16 位)
javascript
^[a-zA-Z0-9_]{6,16}$
解析:
^
表示字符串的开始。[a-zA-Z0-9_]
匹配一个字母(大小写均可)、数字或下划线。{6,16}
表示前面的字符(在这里是 [a-zA-Z0-9_])应该出现 6 到 16 次。$
表示字符串的结束。
举例:
- 输入字符串:"abcd_123dfc"
- 匹配结果:"abcd_123dfc"
3.8 匹配由任意数字、字母、下划线组成的字符串
javascript
^[A-Za-z0-9_]+$
解析:
^
表示字符串的开始。[A-Za-z0-9_]
匹配一个字母(大小写均可)、数字或下划线。+
表示前面的字符(在这里是 [A-Za-z0-9_])应该出现一次或多次。$
表示字符串的结束。
举例:
- 输入字符串:"abcd_123dfcxxx"
- 匹配结果:"abcd_123dfcxxx"
4.正则表达式在 JS 中的应用
JavaScript 中,正则表达式对象自身并没有直接的方法,但是可以通过字符串对象来使用正则表达式,以下是字符串对象中与正则表达式相关的方法:
- match(): 使用正则表达式在字符串中查找匹配的子字符串,并返回一个包含这些匹配项的数组。如果没有匹配项,则返回null。
javascript
const str = 'The rain in Spain stays mainly in the plain';
const regex = /ain/g;
const matches = str.match(regex);
console.log(matches); // ["ain", "ain", "ain"]
- search():使用正则表达式在字符串中查找匹配的子字符串,并返回第一个匹配项的索引。如果没有找到匹配项,则返回-1。
javascript
const str = 'The rain in Spain stays mainly in the plain';
const regex = /ain/g;
const index = str.search(regex);
console.log(index); // 4
- replace():使用正则表达式替换字符串中与模式匹配的子字符串。
javascript
const str = 'The rain in Spain stays mainly in the plain';
const regex = /ain/g;
const newStr = str.replace(regex, 'o');
console.log(newStr); // "The ro in Spain stays moily in the ploin"
- split(): 使用正则表达式将字符串分割成子字符串数组,分割点在匹配正则表达式的位置。
javascript
const str = 'The rain in Spain stays mainly in the plain';
const regex = /\s+/;
const parts = str.split(regex);
console.log(parts); // ["The", "rain", "in", "Spain", "stays", "mainly", "in", "the", "plain"]
总结
正则表达式在我们日常工作经常使用,本文仅讲解了正则表达式的一些简单内容,包括:常用的元字符、运算优先级、修饰符等,帮助大家简单的理解正则表达式含义。随后详细分析了一些常用的正则表达式,希望可以帮助大家达到能够简单使用正则表达式的水准。为了满足大家日常的工作需要,这里再总结一些常用的表达式供大家参考使用:
- 数字:^[0-9]*$
- n位的数字:^\d{n}$
- 至少n位的数字**:^\d{n,}$**
- m-n位的数字:^\d{m,n}$
- 零和非零开头的数字:^(0|[1-9][0-9]*)$
- 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
- 带1-2位小数的正数或负数:^(-)?\d+(.\d{1,2})$
- 正数、负数、和小数:^(-|+)?\d+(.\d+)?$
- 汉字:^[\u4e00-\u9fa5]{0,}$
- 英文和数字:^[A-Za-z0-9]+ <math xmlns="http://www.w3.org/1998/Math/MathML"> 或 [ A − Z a − z 0 − 9 ] 4 , 40 或 ^[A-Za-z0-9]{4,40} </math>或[A−Za−z0−9]4,40
- 长度为3-20的所有字符:^.{3,20}$
- 由26个英文字母组成的字符串:^[A-Za-z]+$
- 由26个大写英文字母组成的字符串:^[A-Z]+$
- 由26个小写英文字母组成的字符串:^[a-z]+$
- 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
- 由数字、26个英文字母或者下划线组成的字符串:^\w+ <math xmlns="http://www.w3.org/1998/Math/MathML"> 或 \w 3 , 20 或 ^\w{3,20} </math>或\w3,20
- 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
- 可以输入含有
^%&',;=?$\"
等字符:[^%&',;=?$\x22]+ - 禁止输入含有
~
的字符:[^~]+ - 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+.?
- InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$
- 手机号码:^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$
- 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
- 身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:
(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
- 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
- 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
- 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
有关正则的知识点还有很多,需要我们继续发掘和深入学习,目前应付工作应该够用。本文有什么写的不对的地方,欢迎各位掘友在评论区批评指正。如果大家觉得本文还不错,欢迎各位大佬点赞+收藏+关注!