资讯专栏INFORMATION COLUMN

你不知道的 javascript正则表达式

MangoGoing / 965人阅读

摘要:正则表达式是用于匹配字符串中字符组合的模式。在中,正则表达式也是对象。注意如果正则表达式设置了全局匹配标志,和的执行会改变正则表达式属性。显示显示方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。

正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。
这些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、replace、search 和 split 方法。
正则表达式对象: 1、创建正则表达式的两种形式 1.1、使用字面量来创建构造函数

一个正则表达式字面量,其由包含在斜杠之间的模式组成/pattern/flags
pattern: 正则表达式的文本。
flags: 正则表达式的标志
例如:全局查找含有hello字符的字符串,忽略字符的大小写

var regexp = /hello/gi
regexp.test(" Hello world")        //true
regexp.test("Say hEllo")    //true
1.2、使用构造函数来创建正则表达式

使用构造函数提供正则表达式的运行时编译,如果你要动态生成一个正则表达式应该选用这种方式
new RegExp(pattern [, flags])
例如:

let regex = new RegExp("ab+c", "img");

构造函数可以接受正则表达式文本和字符串,作为第一个参数, 正则表达式标志作为第二个参数

let regex = new RegExp(/^[a-zA-Z]+[0-9]*W?_$/, "gi");

注意如果构造函数的第一个参数传入的是字符串,它须要经过以下几个步骤的处理:
1.去掉正则表达式文本两头的 /
2.正则表达式文本里面的所有 都要进行转义写成

let regex = new RegExp("^[a-zA-Z]+[0-9]*W?_$", "gi");

当我们要做一个很复杂的查找时,可以像下面这样分解步骤

let str = "^&*()_ 
sdf7$df NN
2、正则表达式对象的lastIndex属性

lastIndex是正则表达式实例的一个读/写整数属性,它指定从哪个索引开始下一个匹配。
The lastIndex is a read/write integer property of regular expression instances that specifies the index at which to start the next match.

var regex1 = new RegExp( "ble", "g" );
var str1 = "table football, foosball";

var judage1 = regex1.test(str1);    
console.log(judage1);                //true
console.log(regex1.lastIndex);       //5 

var judage2 = regex1.test(str1);   
console.log(judage2);                //false
console.log(regex1.lastIndex);       //0 

这里我们可以看到同一个全局检索的正则表达式(含有g),执行多次后,检索的内容竟然是不同的。judage1 为 true,judage2 为false。因为第一次检索后lastIndex会被改变,指向它匹配字符所在处的最后一个索引+1。而之后再次调用正则检索,正则会从上一次lastIndex停止的地方开始检索。所以第一次匹配能够匹配到“ble”,而第二次从上一次“ble”停下的地方开始检索,后面没有“ble”字符,所以judage2 = false。
⭐注意:
如果正则表达式设置了全局匹配标志g,test() 和 exec()的执行会改变正则表达式 lastIndex属性。连续的执行test()方法,后续的执行将会从 lastIndex 处开始匹配字符串

var regex1 = new RegExp( "ble", "g" );
var str1 = "table football, foosball";
console.log(regex1.test(str1))        //true
console.log(regex1.test(str1))        //false

因为多次调用设置了全局匹配标志g的test(), 会导致 regex1的lastIndex 属性改变。所以千万不要在for 循环里面调用含有全局匹配标志g的正则函数,那样匹配验证会出问题。

3、编写一个正则表达式的模式 3.1、使用简单的模式
let regexp = /abc/;        //直接匹配在一个字符串中,是否含有字符"abc"
regexp.test("123abc @#$hh")        //true
3.2、使用特殊字符
let regexp = /ab*c/                //* 是特殊字符,意思是前面一项出现了零个或者多个
regexp.test("123ac @#$hh")                //true
regexp.test("123abbbbbbbbbbc @#$hh")      //true  
regexp.test("123abdc @#$hh")              //false  
4、正则表达式有哪些特殊字符 4.1、简单的特殊字符
字符 含义
是一个转义字符
1.放在普通字符前面将后面的普通字符转义成特殊字符
/d/是匹配一个字符d,而/d/ 就是匹配一个数字
2.放在特殊字符前面,将后面特殊字符转化成普通字符
/A*/是匹配0个至多个A,/A*/就真的是匹配 "A*" 字符
3. 使用 new RegExp("pattern") 的时候不要忘记将 进行转义,因为 在字符串里面也是一个转义字符。
new RegExp("d")只匹配d字符,   new  RegExp("d")  才会匹配数字
^ 匹配输入的开始。如果设置了多行标志m,那么也匹配换行符后紧跟的位置。
例如,/^A/ 并不会匹配 "an A" 中的 "A",但是会匹配 "An E" 中的 "A"。
/^w/m 并不会匹配 "Hello world"中的 "w", 也不会匹配 "Hellon world"(w前面有空格),但是会匹配 "Hello world"
$ 匹配输入的结束。如果设置了多行标志m,那么也匹配换行符前的位置。
例如,/t$/ 并不会匹配 "eater" 中的 "t",但是会匹配 "eat" 中的 "t"。
* 匹配前一个字符0次或多次。等价于 {0,}。
例如,/bo*/会匹配 "A ghost boooooed" 中的 "booooo" 和 "A bird warbled" 中的 "b",但是在 "A goat grunted" 中将不会匹配任何东西。
注意/bo*/ 意思是以b字母开头,后面有0个或多个o,而不是有0个或多个bo
*只针对离它最近的字符
/(bo)*/ 意思才是匹配0个或多个"bo"
. (小数点)匹配除换行符之外的任何单个字符。
例如,/.n/将会匹配 "nay, an apple is on the tree" 中的 "an" 和 "on",但是不会匹配 "nay",因为 "." 会将每条字符串的首部视作有一个换行符
x|y 匹配‘x’或者‘y’。
例如,/green|red/匹配“green apple”中的‘green’和“red apple”中的‘red’
{n} n是一个正整数,匹配了前面一个字符刚好发生了n次。
比如,/a{2}/不会匹配“candy”中的"a",但是会匹配“caandy”中所有的a,以及“caaandy”中的前两个"a"。
{n,m} n 和 m 都是整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。
例如,/a{1, 3}/ 并不匹配“cndy”中的任意字符,匹配“candy”中的a,匹配“caandy”中的前两个a,也匹配“caaaaaaandy”中的前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。
注意:{n,m}之间没有空格
[xyz] 一个字符集合。匹配方括号中的任意字符,包括转义序列。你可以使用破折号(-)来指定一个字符范围。
对于点(.)和星号(*)这样的特殊符号,如果不进行转义,在一个字符集中没有特殊的意义。
/[ad]/g 只会匹配“add 20190726”中的 ‘a’和‘d’,并不会匹配数字
如果进行了转义
/[ad]/g 就会匹配“add 20190726”中的‘a’和所有数字
[^xyz] 一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。
使用方法同[xyz], 只是 [^xyz]是不包含
例如,[^abc] 和 [^a-c] 是一样的。他们匹配"brisket"中的‘r’,也匹配“chop”中的‘h’。
d 匹配一个数字。
等价于[0-9]。
例如, /d/ 或者 /[0-9]/ 匹配"B2 is the suite number."中的"2"。
D 匹配一个非数字字符。
等价于[^0-9]。
例如, /D/ 或者 /[^0-9]/ 匹配"B2 is the suite number."中的"B"。
w 匹配一个单字字符(字母、数字或者下划线)。
等价于[A-Za-z0-9_]。
例如, /w/ 匹配 "apple," 中的 "a","$5.28,"中的 "5" 和 "3D." 中的 "3"。
W 匹配一个非单字字符。
等价于[^A-Za-z0-9_]。
例如, /W/ 或者 /[^A-Za-z0-9_]/ 匹配 "50%." 中的 "%"
4.2、高级的特殊字符

更新中

正则表达式对象常用的3种方法: 1、RegExp.prototype.toString()

RegExp 对象并没有继承 Object.prototype.toString(),而是覆盖了 Object 对象的 toString() 方法,对于 RegExp 对象,toString 方法返回一个该正则表达式的字符串形式。

myExp = new RegExp("a+b+c");
console.log(myExp.toString());       // 显示 "/a+b+c/"

foo = new RegExp("bar", "g");
console.log(foo.toString());         // 显示 "/bar/g"
2、RegExp.prototype.test()

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

let _regexp = new RegExp("Wo" , "i");
let str = "hello world!";
let result = _regexp.test(str);
console.log(result);    //true
3、RegExp.prototype.exec()

exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。
如果匹配成功,exec() 方法返回一个数组,并更新正则表达式对象的属性。返回的数组将完全匹配成功的文本作为第一项,将正则括号里匹配成功的作为数组填充到后面。

var params = "user"
var regexp = new RegExp("[?#&]" + params + "=([^&#]*)", "i")
var str = "www.qq.com?user=Tom&psw=123456";
var res = regexp.exec(str);
console.log(res)    // ["?user=Tom", "Tom"]

可以看到返回数组的第一个元素就是整个的匹配模式所匹配到的字符串,而第二个匹配到的字符恰好是参数值。这是exec匹配返回的规则:第一个元素为整个的匹配字符串,从第二个参数开始返回模式中每一个()自身正则所匹配的字符串。这里面([^]*)返回的就是不以&或#开头的字符串,即等号后面对应的参数Tom。

然后我们给params 再加一个括号, 便把params(匹配到的)也输出来了。

var params = "user"
var regexp = new RegExp("[?#&]" + "(" +params+ ")" + "=([^&#]*)", "i")
var str = "www.qq.com?user=Tom&psw=123456";
var res = regexp.exec(str);
console.log(res)    // ["?user=Tom", "user", "Tom"]
String 对象使用正则的几种方法 1、match方法

match 方法检索返回一个字符串匹配正则表达式的的结果。
当你不使用g标志,即不进行全局检索时, 仅返回第一个完整匹配及其相关的捕获组(Array)。

let str = "……ssdf #$%^& ab Abbbbb ABC153**";
let regexp = new RegExp("ab", "i");
let result = str.match(regexp)
console.log(result)

输出:
[
  "ab",         //第一个完整的匹配项       
  index: 13,    //匹配结果的开始位置
  input: "……ssdf #$%^& ab Abbbbb ABC153**",        //搜索的字符串
  groups: undefined        //一个捕获组数组 或 undefined(如果没有定义命名捕获组)
]

如果match没有匹配到任何项,则会直接返回null

let regexp2 = new RegExp("xxx", "i");
let result2 = str.match(regexp2)
//null

⭐注意match还有两种特殊的使用情况:
1、match 如果传入一个非正则表达式对象,则会隐式地使用 new RegExp(obj) 将其转换为一个 RegExp

let result3 = str.match("ab")    //str.match("ab") = str.match(new RegExp("ab"));

输出还是和之前一样:
[
  "ab",
  index: 13,
  input: "……ssdf #$%^& ab Abbbbb ABC153**",
  groups: undefined
]

2、如果你没有给出任何参数并直接使用match() 方法 ,你将会得到一 个包含空字符串的 Array :[""] ,而不是null。

let result 4 = str.match()

输出:
[
  "",
  index: 0,
  input: "……ssdf #$%^& ab Abbbbb ABC153**",
  groups: undefined
]
2、replace方法

通过正则查找到匹配项,然后替换这些字符,注意replace方法只会返回替换后的结果,不会改变原字符串。
使用示例:
1、直接替换字符串默认只会替换第一次匹配的项。

let str = "……ssdf #$%^& ab Abbbbb ABC153**";
let result = str.replace("s", 77)
console.log(result)        //……77sdf #$%^& ab Abbbbb ABC153**
默认只会替换第一个s

2、正则加g标志,全局替换所有匹配的字符

let str = "……ssdf #$%^& ab Abbbbb ABC153**";
let reg = /ab/gi
let result = str.replace(reg, "T")
console.log(result)        //……ssdf #$%^& T Tbbbb TC153**
所有的ab都替换成了 T
3、替换字符串支持插入下面的特殊变量名

① $& 插入匹配的子串

let str = "刘一、陈二、张三、李四、王五、赵六、孙七、周八、吴九、郑十"
let reg = new RegExp("[张赵孙][三七八]", "gi")
let result = str.replace(reg, "新名字")
console.log(result)
//刘一、陈二、新名字、李四、王五、赵六、新名字、周八、吴九、郑十

let result2 = str.replace(reg, "新名字$&");
console.log(result2)
//刘一、陈二、新名字张三、李四、王五、赵六、新名字孙七、周八、吴九、郑十

② $` 插入当前匹配的子串左边的内容。

let result3 = str.replace(reg, "新名字$`");
console.log(result3)
//刘一、陈二、新名字刘一、陈二、、李四、王五、赵六、新名字刘一、陈二、张三、李四、王五、赵六、、周八、吴九、郑十

③ $" 插入当前匹配子串右边的内容

④ $n 插入第n个括号匹配的字符串
⭐注意:
new RexExp()第一个参数需要是一个含有正则的文本
n 是个小于100的非负整数
索引是从1开始(即插入第一个括号里面匹配的内容为 $1)
例子:

var re = /(w+)s(w+)/;
var str = "John Smith";
var newstr = str.replace(re, "$2, $1");
console.log(newstr);    // Smith, John
//分析第一个括号里面匹配到了John 即 $1是John,第二个括号里面匹配到了 Smith, 即$2 为Smith
3、search方法

如果匹配成功,则 search() 返回正则表达式在字符串中首次匹配项的索引;否则,返回 -1。

let str = "Hello AbC aBC ABC abc"
let result = str.search(/abc/gi);
console.log(result)    //6
//注意即使你用了全局查找标志g,search也只会返回首次匹配的索引,索引走0开始
4、Split 方法
// split 方法默认搜素全局,所以不管你的正则是否使用了g标志,结果都一样
let str = "Hello AbC aBC ABC abc"
let result = str.split(/[a]/);
let result2 = str.split(/[a]/g);
console.log(result)        //[ "Hello AbC ", "BC ABC ", "bc" ]
console.log(result2)       //[ "Hello AbC ", "BC ABC ", "bc" ]

//split 可以限制分割几块字符串,当返回的分割字块到达限制大小时分割停止
let result3 = str.split(/[a]/g, 2);
console.log(result3)        //[ "Hello AbC ", "BC ABC " ]

//当分割的限制大于返回数组的长度时
let result3 = str.split(/[a]/g, 3000);
console.log(result3)        //[ "Hello AbC ", "BC ABC ", "bc" ]
参考资料
MDN web docs 正则表达式

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106146.html

相关文章

  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    jsbintask 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    muddyway 评论0 收藏0
  • Node.js 指南(不要阻塞事件循环或工作池)

    摘要:为什么要避免阻塞事件循环和工作池使用少量线程来处理许多客户端,在中有两种类型的线程一个事件循环又称主循环主线程事件线程等,以及一个工作池也称为线程池中的个的池。 不要阻塞事件循环(或工作池) 你应该阅读这本指南吗? 如果你编写的内容比简短的命令行脚本更复杂,那么阅读本文应该可以帮助你编写性能更高、更安全的应用程序。 本文档是在考虑Node服务器的情况下编写的,但这些概念也适用于复杂的N...

    hatlonely 评论0 收藏0
  • 翻译连载 | 第 9 章:递归(上)-《JavaScript轻量级函数式编程》 |《你不知道JS》

    摘要:一旦我们满足了基本条件值为,我们将不再调用递归函数,只是有效地执行了。递归深谙函数式编程之精髓,最被广泛引证的原因是,在调用栈中,递归把大部分显式状态跟踪换为了隐式状态。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTML 最坚实的梁柱;...

    MasonEast 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<