代码改变世界

看了就懂的,正则基础小结

2021-03-29 00:56  罗小二  阅读(321)  评论(0)    收藏  举报

 

查找特定字符,替换特定文本,数据有效性的验证,以及看框架源码等,或多或少都会用到正则表达式。

文章能了解:如何创建正则,如何理解编写正则,以及常用方法。看着上面那张图,大概率入个门不会懵了。

概要:

  1. 两种创建正则的方式
  2. 编写正则表达式规则
  3. 常用方法
  4. 总结

1. 两种创建RegExp对象方法

Regular expressions are patterns used to match character combinations in strings. In JavaScript, regular expressions are also objects. 

正则表达式是用于匹配字符串中字符组合的模式。用来处理字符串的规则。

1.1字面量方式

字面量方式,由包含在 斜杠之间 的模式组成:

var re = /abc/; 

脚本加载后,正则表达式字面量就会被编译。当正则表达式保持不变时,使用此方法可获得更好的性能

举个小例子:
//字符串中是否包含123
let str = "123xiaoer";
let reg = /123/;
reg.test(str); //=>true

1.2RegExp对象的构造函数

RegExp对象的构造函数:

var re = new RegExp("abc");

在脚本运行过程中,用构造函数创建的正则表达式会被编译。如果正则表达式将会改变,或者它将会从用户输入等来源中动态地产生,就需要使用构造函数来创建正则表达式。

举个小例子:在Chrome浏览器页面查找功能(ctrl + f)

用户输入 字符串“Regexp”,动态生成一条正则表达式,查找出文中RegExp字符串。  

2.编写正则表达式规则

正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的规则。规则描述在搜索文本时要匹配的一个或多个字符串。
编写正则表达式需要了解:
  • 简单字符(数字,字母,逗号,@符等按照字面含义匹配的符号,非特殊字符)
  • 特殊字符(又叫元字符,一些有特殊含义的字符)
    • \
    • 字符类(代表一个类)
    • 重复(量词,出现的次数)
    • 选择、分组和引用
    • 匹配位置
  • 修饰符(i,m,g)

2.1 特殊字符

2.1.1  反斜杠 \

 \ :指示 \  相连接的字符被特殊对待“转义”。它表现为两种方式之一。

对于通常按字面意义处理的字符,表示下一个字符是特殊字符,不应按字面意义进行解释。普通字符变特殊-> 如 \d

对于通常被特殊对待的字符,指示下一个字符不是特殊字符,应按字面意义进行解释。特殊字符变普通-> 如 \\d

2.1.2  直接量

常用的:

字符 含义
\n

换行符

\r

回车符

\uxxxx

匹配查找xxxx(四个十六进制数字)规定的Unicode字符。

 

2.1.3  字符类

特殊说明:

字符 含义
[......]

1.字符集。 匹配任何一个包含在方括号中的字符。[^.....]以^开头,匹配任何一个没有包含在方括号[.....]中的字符

2.此处需要注意连字符 -。可以使用连字符来指定字符范围[1-5],但如果连字符显示为方括号中的第一个或最后一个字符,则被视为作为普通字符-。

3.在方括号中出现\ 时需注意不一定是字符本意[\d] 相当于[0-9] 而不是 "\" 或 d。

.

1.匹配除行终止符之外的任何单个字符

2.在字符集内(方括号中),点失去了它的特殊意义,并与文字点匹配。

 

举个小例子:正则表达式/[xiaobu123]/ ( 使用的工具Regexper),展示如图

只要字符串从左到右匹配出现[xiaobu123]括号中的任意一个字母或数字,就满足此正则表达式规则/[xiaobu123]/ 

连字符 -出现在方括号中,可能是起连字符作用比如[12-47](匹配1,2,3,4,7这几个数字),也可能是匹配字符本身比如[-47]

常用的字符类:

常用匹配字符含义
\d 匹配任何数字(阿拉伯数字), 相当于 [0-9]
\D 匹配任何非数字(阿拉伯数字)的字符。相当于[^0-9]
\w 匹配英文字母数字,下划线。相当于 [A-Za-z0-9_]
\W 匹配任何不是英文字母数字,[^A-Za-z0-9_]
\s 匹配任何 Unicode空白符的字符,空格,制表符,换页符等
\S 匹配任何非 Unicode空白符的字符。

 

2.1.4  重复(量词,出现的次数)

指定字符重复的标记:

语法含义

{n,m}

匹配前一项至少n次,但不超过m次
{n,} 匹配前一项至少n次,或更多次
{n} 匹配前一项n次
匹配前一项0次或1次,等价于 {0,1}
+ 匹配前一项至少1次或多次,等价于{1,}
* 匹配前一项0次或多次,等价于 {0,}

 

补充一个记忆点: ?+*(问就加一颗星~~)

举个小例子:正则表达式/ab{3}/ ( 使用的工具Regexper),展示如图,看图方便理解

即字符串从左到右包含abbb串就符合此正则表达式规则

?+ * 结合图理解:

正则的一大特性贪婪性: 试图匹配尽可能多的字符串

x*?
x+?
x??
x{n}?
x{n,}?
x{n,m}?
默认情况下,像 * 和 + 等这样的量词是“贪婪的”,这意味着它们试图匹配尽可能多的字符串。在这些量词后面加 ?,这些量词就变成非贪婪的了,意味着一旦找到匹配项,就停止。
 
如图/\d+/和/\d+?/对同一字符串的匹配:
左图由于贪婪性,匹配尽可能多的字符串结果为2020,右图非贪婪匹配到数字2就停止匹配了。

2.1.5  选择、分组和引用

选择:

语法含义

|

或,匹配竖线左边或右边,比如/ab|bc/ 即字符串中有ab 或bc 即可

 

举个小例子:正则表达式/12|28/ ( 使用的工具Regexper),展示如图

只要字符串从左到右匹配出现12或者28,就满足此正则表达式规则/12|28/ 

分组和引用:

语法含义

(xyz)

1.分组: 将xyz的项分成一个组,以便整体匹配比如 /(abc){2}/ ,abc这一组字符串连续出现两次才能匹配

2.捕获:匹配括号的里面的项并记住匹配项。例如,/(foo)/匹配并记住“foo bar”中的“foo” 

3.引用:正则表达式可能具有多个捕获组。捕获组中左括号的顺序数字为x,\x 则为第x个组捕获的字符的引用。 

(?:xyz)

1.只将xyz的项分成一个组,但不捕获记忆。(只分组,不捕获)

2.捕获组会产生性能损失。 如果不需要调出匹配的子字符串,请使用非捕获括号

 补充:如果只分组,不捕获引用,就使用(?:xyz)

举几个小例子:正则表达式/xiaobu(123|456)ha\1/ ( 使用的工具Regexper),展示如图:

group1 捕获的是123,后面的\1 引用的就是123,group1 捕获的是456,后面的\1 引用的就是456。

正则表达式/xiaobu(?:123|456)ha(abc)\1/ ( 使用的工具Regexper),展示如图: 可以和上图做比较(?:123|456) 并没有被捕获记忆。

2.1.6  匹配的位置

符号指定字符串匹配的“合法”位置:指定位置不是实际的字符

  • 首尾位置
  • 单词边间
  • 条件指定(断言)

首尾位置指定符号

语法含义

^

1.匹配输入字符串的开始位置
2.注意与在方括号[]表达式中使用区分方括号[]表达式中使用表示不接受该方括号表达式中的字符集合[^......]

$

匹配输入字符串的结尾位置

 

以/^xiao(reg|exp)bu$/ 为例  ( 使用的工具Regexper),展示如图:

单词边间:

语法含义

\b

匹配一个单词的边界

\B

匹配非单词边界的位置

 

\b 匹配一个单词的边界:指定\w和\W 之间的位置、字符\w和字符串开头之间位置、字符\w和字符串结尾之间位置。

用法:
/\b表达式/ 匹配符串中单词以表达式开头部分(单词起始位置)
/表达式\b/ 匹配字符串中单词以表达式结尾部分(单词结束位置)
/\b表达式\b/ 匹配字符串中存在表达式的单词
举个例子:
var rep = /\bxiao/
var str = "xiaobu123 happy"
var res = str.replace(rep,"haha") 

结果

var rep = /\Bis/
var str = "This is a test"

正则会匹配单词This 中的is

 条件指定: ?=、?<=、?!、?<!  
 
语法表达含义
x(?=y)
向前断言: x 被 y 跟随时匹配 x。例如,对于/Jack(?=Sprat)/,“Jack”在跟有“Sprat”的情况下才会得到匹配./Jack(?=Sprat|Frost)/ “Jack”后跟有“Sprat”或“Frost”的情况下才会得到匹配。不过, 匹配结果不包括“Sprat”或“Frost”
x(?!y)  
向前否定断言: x 没有被 y 紧随时匹配 x。例如,对于/\d+(?!\.)/,数字后没有跟随小数点的情况下才会得到匹配。
(?<=y)x
向后断言: x 跟随 y 的情况下匹配 x。例如,对于/(?<=Jack)Sprat/,“Sprat”紧随“Jack”时才会得到匹配。对于/(?<=Jack|Tom)Sprat,“Sprat”在紧随“Jack”或“Tom”的情况下才会得到匹配。不过,匹配结果中不包括“Jack”或“Tom”。(有旧版浏览器兼容问题)
(?<!y)x 
向后否定断言: x 不跟随 y 时匹配 x。例如,对于/(?<!-)\d+/,数字不紧随-符号的情况下才会得到匹配。(有旧版浏览器兼容问题)
总结,就是x在y前出现匹配,就是x不在y前出现匹配,就是x在y后出现匹配,就是x不在y后出现匹配,

2.2. 修饰符

正则表达式的修饰符,用来修饰规则

常用的有 i,m,g : (记忆点,图片标签img)

语法含义

i

执行不区分大小写的匹配,搜索时不区分大小写: A 和 a 没有区别。

m

多行匹配。(这种修饰符下,边界字符 ^ 和 $ 匹配每一行的开头和结尾,多行,而不是整个字符串的开头和结尾)

g

全局匹配,查找所有的匹配项而不是第一个就停止。

 

 正则的一个特性懒惰性:查找到一个匹配项就是停止查找,如果要全局查找就需要加上修饰符g

如图/\d+/g和/d+/对同一字符串的匹配:左图是全局匹配,会查找所有匹配项。右图不是全局匹配,查找到第一个满足的项就停止查找了。

3.常用方法

正则常用的方法:

  • RegExp对象
    • exec (需要捕获结果时使用)
    • test (只是为了判断是否匹配时使用)
  • String对象
    • match
    • replace

3.1 RegExp对象

RegExp实例的属性 lastIndex:表示从哪里开始下一个匹配。默认值为 0。(还有其它属性本文查看文档)

如果正则表达式设置了全局标志,lastIndex才会在每次匹配中变化

3.1.1 exec()

RegExp实例的属性 lastIndex:表示从哪里开始下一个匹配。默认值为 0。

exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。

匹配时返回一个数组:包括第一个完整匹配的字符串和相关的捕获组,index,input 属性。
对象索引/属性表达的意思
数组 0
数组第0位为,第一个匹配的字符串
[1]~[n] 数组第n位:表示正则表达式捕获组中左括号的顺序数字为n,第n个组捕获的字符
index
匹配到的字符位于原始字符串的基于0的索引值
input  
原始字符串
 
举个例子:
var re = /\w(\d+)/
var str = "xiaobu2020happy2021haha123"
var result = re.exec(str)
console.log(result)
console.log(re.lastIndex)
// 输出
// [
//     'u2020',  匹配的全部字符串,数组第0位
//     '2020',   括号中的分组捕获,数组第1位
//     index: 5,  匹配到的字符位于原始字符串的基于0的索引值
//     input: 'xiaobu2020happy2021haha123', 原始字符串
//     groups: undefined
//   ]
// 0

因为正则表达式的懒惰性多次执行re.exec(str)结果也不会改变。

要想将整个字符串查找匹配就要修改,正则的规则添加修饰符g,多次执行re.exec(str)结果发生了变化,此时lastIndex 也变化了

如果正则表达式设置了全局标志,exec() 的执行会改变正则表达式   lastIndex属性

3.1.2 test() 

test() 方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。返回 true 或 false。

如果正则表达式设置了全局标志,test() 的执行会改变正则表达式   lastIndex属性

test()使用同 exec()方法,只是返回结果不同,返回true或false。

3.2 String 对象

3.2.1 match()

match() 方法检索返回一个字符串匹配正则表达式的结果。
  • 未使用g标志,返回结果同exec()
  • 使用g标志,则将返回与完整正则表达式匹配的所有结果,但不会返回捕获组。

未使用g标志,返回结果同exec()

var re = /\w(\d+)/
var str = "xiaobu2020happy2021haha123"
var result = str.match(str)

使用g标志,则将返回与完整正则表达式匹配的所有结果,但不会返回捕获组。

3.2.2 replace()

str.replace(regexp|substr, newSubStr|function)

 文章感兴趣的是 str.replace(regexp,function)这种用法,其它用法参考文档

function 被内部调用时接收的参数,跟exec()执行得到的结果一致,按顺序接收到,匹配的字符串,捕获组展开,index值(匹配到的字符位于原始字符串的基于0的索引值,input被匹配的原字符串。

function return 的值就是用来替换匹配到的字符串的值

举个例子:

var re = /\w(\d+)/
var str = "xiaobu2020happy2021haha123"
var result = str.replace(re, function() {
    console.log(arguments)
})

如果使用g标志,正则匹配多少次,就执行多少次function。

4. 总结

文章整理了相关资料,比较基础,没有写到正则的回溯,有兴趣的同学可以深入下去。

文章理解不准确之处,还请斧正。欢迎一起讨论学习。

 

 

书籍:《JavaScript权威指南》

工具:Regexper

文章:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp