JavaScript正则表达式

正则表达式( Regular Expressions)

介绍

什么是正则表达式?

由以下两种字符组成的文字模式

​ 1、普通字符(例如26个英文字母、数字等)

​ 2、特殊字符(有特殊含义的,例如.\等)

该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符串模式与所搜索的字符串进行匹配。

为什么使用正则表达式?

​ 查找、替换、数据有效性验证

初始正则表达式

正则表达式的两种创建方式

​ 字面量创建方式

var reg = /js/

​ 构造函数创建方式

var reg = new RegExp('js')

两种创建正则表达式的区别?

​ 当正则匹配的规则是个变量时,只能用构造函数创建方式,如:

var str = 'I love Js'
var userInput = 'love'	//模拟用户输入
var pattern = new RegExp(userInput,'i')
console.log(parttern.test(str))	//true
console.log(parttern.exec(str))	//['love']

简单的小例子

var str = 'I love js'
var pattern1 = /js/
console.log(pattern1.test(str))	//true
console.log(pattern1.exec(str))	//['js']
var pattern2 = /Js/
console.log(pattern2.test(str))	//false
console.log(pattern2.exec(str))	//null

test:匹配到返回true,否则返回false

exec:匹配到返回数组,否则返回null

正则匹配是区分大小写的,怎样忽略大小写呢?我们接着学习,便知

正则表达式的模式修饰符

i ignoreCase 忽略大小写

g global 全局匹配

m multiline 多行匹配

var str = 'I love Js'
var pattern1 = /js/i
console.log(pattern1.test(str))	//true
console.log(pattern1.exec(str))	//['Js']

我们试着用另外的一种正则创建方式来做上题

var str = 'I love Js'
var pattern = new RegExp('js','i')
console.log(pattern.test(str))	//true
console.log(pattern.exec(str))	//['Js']

后面的两个模式修饰符,后面慢慢介绍。

简单的转义字符

转义字符: \

转义:将一种字符从一种含义转换为另一种含义

\n 换行

\t 制表符

\x0A 等同于 \n

\x61 就是a字符

\u0009 unicode编码 可以匹配中文字符

在正则的构造函数创建方式中,传入的是字符串,转义字符的数量是字面量方式的**双倍,**如下:

var pattern = /\b/ 
var pattern = new RegExp('\\b')

var pattern = /\\/
var pattern = new RegExp('\\\\')
字符类

[ abcd ] 匹配里面的任意一个字符,若水三千,只取一瓢,只要有一个匹配到,就是正确的。

var str = 'javascript'
var pattern = /[bcd]/ 
var result = pattern.exec(str)
console.log(result) //['c']

[ ^abcd ] 匹配除了a / b / c / d 以外的任意一个字符

var str = 'javascript'
var pattern = /[^abcd]/ 
var result = pattern.exec(str)
console.log(result) //['j']

[a-z] 匹配a到z字符的任意一个字符

[a-zA-Z] 匹配英文字符

[0-9] 匹配数字字符

常用的字符

. 除了换行符以外的任意字符

var str = '3.1415926'
var pattern = /\./	//匹配小数点
var pattern = /./	//匹配除了换行符以外的字符
console.log(pattern.exec(str))	// 3	

[a-zA-Z0-9_] 等同于 \w

[^a-zA-Z0-9_] 等同于 \W

[0-9] 等同于 \d

[^0-9] 等同于 \D

\s 既能匹配空格又能匹配制表符,等一些uniode空格类的字符

\S 匹配除了空格、制表符和unicode空格类的字符

扩展: /\d\s/ 匹配数字空格,如‘9 ’ /[\d\s]/ 任意一个数字或者空格

量词

​ 指定匹配的次数,如

var str = '110'
var pattern = /\d{3}/  //匹配3次 \d
console.log(pattern.exec(str))

​ 指定匹配的次数范围

var str = '110'
var pattern_1 = /\d{1,2}/
var pattern_2 = /\d{1,}/ //至少匹配一次 等同于 /\d+/ 
var pattern_3 = /\d{0,}/ //至少匹配一次 等同于 /\d*/ 
var pattern_4 = /\d?/ // 等同于/\d{0,1}/ ==> ? === {0,1}
console.log(pattern_1.exec(str))	// 11
console.log(pattern_2.exec(str))	// 110
console.log(pattern_3.exec(str))	// 110
console.log(pattern_4.exec(str))	// 1

贪婪匹配:正则在默认的情况下,是贪婪的匹配,比如上面的pattern_1模式,只要情况允许,尽可能的多的进行匹配,贪婪匹配只存在于量词中

我们如何将贪婪匹配,转换为非贪婪匹配呢?

在正则后面加上一个问号,如

var str = 'aaab'
var pattern_1 = /a+/
var pattern_2 = /a+?/
console.log(pattern_1.exec(str))	// aaa 贪婪匹配
console.log(pattern_2.exec(str))	// a 非贪婪匹配

注意以下代码

v.ar str = 'aaab'
var pattern = /a+?b/
console.log(pattern.exec(str)) // aaab

问号只是尽可能的匹配

再来看一组案例,匹配<td><p>a</p></td> ?

var str = '<td><p>a</p></td><td><p>b</p></td>'
var pattern_1 = /<td>.*<\/td>/
var pattern_2 = /<td>.*?<\/td>/
console.log(pattern_1.exec(str))	//<td><p>a</p></td><td><p>b</p></td>
console.log(pattern_2.exec(str))	//<td><p>a</p></td>

如果不是非贪婪匹配,答案是不对的。

选择、分组和引用

选择

var str = 'css html js'
var pattern_1 = /html|css|js/
var pattern_2 = /c|css/
console.log(pattern_1.exec(str)) // css
console.log(pattern_2.exec(str)) // c

选择匹配是从左向右匹配,一旦匹配上了就忽略后面的匹配项

分组和引用

匹配多个ab?

var str = 'abab'
var pattern = /(ab)+/
console.log(pattern.exec(str)) //['abab','ab']

()内的表示分成一个组,组里的内容是一个整体,在匹配的时候,括号会有捕获性,即对括号里再进行匹配一次。

那么如何取消捕获呢?

var str = 'abab'
var pattern = /(?:ab)+/ //在前面加个 ?: 就可以取消括号的捕获性
console.log(pattern.exec(str)) //['abab']

多个分组的情况——平行的分组

var str = 'abcd'
var pattern = /(ab)(c)/
console.log(pattern.exec(str)) //['abc','ab','c']

多个分组的情况——嵌套的分组

var str = 'abcd'
var pattern = /(a(b(c)))/
console.log(pattern.exec(str)) //['abc','abc','bc','c']

分析:我们先把整体的括号看成没有,匹配整个模式,然后从左往右数,第一个括号为第一分组,第二个括号为第二个分组,第三个括号为第三个分组。分组要进行捕获性的匹配。

分组

var str = 'ab cd ab'
var pattern = /(ab) cd \1/	// \1代表第一个分组
console.log(pattern.exec(str)) //['ab cd ab','ab']

以上分组在实际中的应用,如下代码:

var str = '<text><a>这是一段文字</a></text>'
var pattern = /<([a-zA-Z]+)>(.*?)<\/\1>/
console.log(pattern.exec(str)) //['<text><a>这是一段文字</a></text>','text','<a>这是一段文字</a>']

扩展:exec函数,我们很早就接触了,但是在没有分组的情况下,只有一个数值。有分组后,就有多个数值。在这个数组中还有两个属性,index和input。

index是匹配的索引值,input是匹配的内容。注意不是捕获的。

位置匹配

首尾匹配

var str = 'js'
var pattern = /^js/ // ^匹配以js开头的 
console.log(pattern.exec(str))

注意不要和/[^0-9]/里的搞混了

var str = 'html js'
var pattern = /js$/ // $ 只能匹配以js结尾的 
console.log(pattern.exec(str))

单词边界匹配

var str = 'hello world nihao'
var pattern = /\bhello\b/
console.log(pattern.exec(str))

@、^、&等都是单词的边界

前瞻性匹配

var str = 'javascript'
var pattern = /java(?=script)/ //只有java后面跟的是script时,才匹配java
console.log(pattern.exec(str))

负向前瞻性匹配

var str = 'javascript'
var pattern = /java(?!script)/ //只有java后面跟的不是script时,才匹配java
console.log(pattern.exec(str))
RegExp对象的实例方法

我们在之前只是简单的使用exec、test方法,这里我们仔细讲一下。

exec方法

var str = 'js js js'
var pattern = /js/g
console.log(pattern.exec(str))//["js", index: 0, input: "js js js", groups: undefined]
console.log(pattern.exec(str))//["js", index: 3, input: "js js js", groups: undefined] 
console.log(pattern.exec(str))//["js", index: 6, input: "js js js", groups: undefined]
console.log(pattern.exec(str))//null
console.log(pattern.exec(str))//["js", index: 0, input: "js js js", groups: undefined]

分析:index为匹配的是str中的第几个。当模式匹配为全局匹配时,每匹配一次,pattern.lastIndex会记录当前匹配完成后的后一个位置的索引。直到结束时,pattern.lastIndex的值会置为0

test方法

var str = 'js js js'
var pattern = /js/g
console.log(pattern.test(str))//true
console.log(pattern.test(str))//true
console.log(pattern.test(str))//true
console.log(pattern.test(str))//false
console.log(pattern.test(str))//true

test方法其实exec方法类似,只不过返回的是布尔值,分析如exec方法

其余方法

var pattern = new RegExp('a\\nb')
console.log(pattern.toString()) // '/a\nb/'
console.log(pattern.toLocaleString()) // '/a\nb/' 转换为具有本地特色的字符串
console.log(pattern.valueOf() === pattern) // true

这些方法都是继承过来的,是Object函数的原型对象里的方法。

RegExp对象的实例属性和构造函数属性

1、实例属性

var str = 'js js js'
var pattern = /js/ig
console.log(pattern.ignoreCase)	//true 判断pattern后面是否带 i
console.log(pattern.global) //true 判断pattern后面是否带 g
console.log(pattern.multiline)	//false 判断pattern后面是否带 m
console.log(pattern.source)	// 和toString类似,都是返回以字面面量类似的字符串
console.log(pattern.lastIndex)  //上面已经进行了介绍,这里就不过多的介绍了

2、构造函数属性

 var str = 'js js js'
 var pattern = /(j)s/
 pattern.exec(str)  
console.log(RegExp.input)	// 'js js js' ,输出待匹配的字符串
console.log(RegExp.$_)	//RegExp.input的别名
console.log(RegExp['$_'])
console.log(RexExp.lastMatch)	//js 输出最近的一次匹配到的值
console.log(RegExp['$&'])	//RegExp.lastMatch的别名
console.log(RegExp.leftContext) // '' ,输出匹配后,剩余的左边的字符串
console.log(RegExp['$`'])//RegExp.leftContext的别名
console.log(RegExp.rightContenxt) //' js js',输出匹配后,剩余的右边的字符串
console.log(RegExp["$'"])//RegExp.rightContext的别名
console.log(RegExp.lastParen)// 'j' ,输出最近的一次分组中捕获的内容
console.log(RegExp["$+"])//RegExp.lastParen的别名
console.log(RegExp.$1)	//'j' 输出第一个分组中内容
String对象中与正则表达式相关的方法

search方法

var str = 'html js js'
var pattern = /js/g
console.log(str.search(pattern))//-5,返回第一次匹配到的素引,与g无关
//我们还可以直接在search中传入字符串,当然,这是将这里的字符串通过构造函数自动转化为正则的
console.log(str.search('js'))	// -5

match方法

var str = 'js js js'
var pattern = /(j)s/
console.log(str.match(pattern))	// ['js','j']
var str = 'js js js'
var pattern = /(j)s/g
console.log(str.match(pattern))	// ['js','js','js']

match方法和exec方法有什么区别?

match:非全局的情况下才会返回分组中匹配到的内容,全局匹配只能匹配到所有匹配到的字符。

exec方法:无论是否全局匹配都会返回分组中匹配到的内容,都只会返回当前匹配到的一个内容,而不是全部返回。

这里介绍一下模式修饰符 m 的作用?

多行匹配 m 一般和尾修饰符,前修饰符,全局匹配一块用,如下代码所示

var str = '1.js\n2.js\n3.js'
var pattern = /js$/mg
console.log(str.match(pattern)) //['js','js','js'],每一行匹配到的js
var pattern = /js$/g
console.log(str.match(pattern) //['js'],只能匹配到一个,换行符没有什么用

split方法

不用正则时的用法

var str = 'html,css,js'
console.log(str.split(',')) //['html','css','js']

用正则时的用法

var str = 'html,css,js'
var patterm = /,/g //加不加g是无所谓的,split默认全局匹配
console.log(str.split(pattern)) //['html','css','js']

这样,用正则和不用正则不就没什么区别了吗!!!肯定不是这样的,如下所示

var str = 'html  ,   css ,  js'
var patterm = /,/
console.log(str.split(pattern)) //['html  ','   css','  js']

待匹配的字符串中,里面有不等的空格,我们用不用正则的方法显然是不能匹配出将空格去掉的字符串数组。这里我们可以用正则的方法,如下代码所示:

var str = 'html  ,   css ,  js'
var patterm = /\s*,\s*/
console.log(str.split(pattern)) //['html','css','js']

replace方法

可以直接传字符串作为参数

var str = 'I love js js'
console.log(str.replace('js','html'))// 'I love html js'

字符串传参,只能将第一个匹配到的改变值。不能进行全局替换。我们用正则的方式,可以进行全局替换,如下代码所示:

var str = 'I love js js'
var pattern = /js/g
console.log(str.replace(pattern,'html'))// 'I love html html'

replace正则的第一个用法

var str = 'I love js'
var pattern = /(js)/
document.write(str.replace(pattern,'<strong style="color:red">$1</strong>'))

replace正则的第二个用法:过滤敏感词

var str = '你好匹配不好匹配匹配太好匹配匹配你好不好'
//这里的的你好、不好、太好是敏感词汇
var pattern = /你好|不好|太好/g
console.log(str.replace(pattern,function($0,$1){//$0表示匹配到的内容,$1表示第一个分组匹配到的内容,这里没有分组
    var result = ''
    for(var i = 0;i < $0.length;i++){
        result +='*'
    }
    return result
}))
常用的正则验证

验证用户输入的是不是QQ号?

QQ号的规则:1.全是数字 、2.首位不能为0、3.最少5位(10000)、4.目前最多11位

var pattern = /^[1-9]\d{4,}$/

验证用户昵称?

昵称规则:1.2-18位 、2.中英文、数字及下划线

var pattern = /^[\u4e00-\u9fa5a-zA-Z0-9_]{2,18}$/
var pattern = /^[\u4e00-\u9fa5\w]{2,18}$/

验证密码是否合法?

密码规则:1.6-18位 、 2.不能用空白字符 、 3.区分大小写

var pattern = /^\S{6,16}$/
var pattern = /^[\w~!@#$%^\]{6,16}$/	//穷举法

去除字符串首位的空白字符?

var str = '    Alex    '
var pattern = /^\s+|\s+$/g //第一种方式
console.log('|'+str.replace(pattern,'')+'|') 
var str = '    Alex    '
var pattern1 = /^\s+/ //第二种方式
var pattern2 = /\s+$/
console.log('|'+str.replace(pattern1,'').replace(pattern2,'')+'|') 

封装成一个方法

function trim(str){
    return str.replace(/^s+/,'').replace(/\s+$/,'')
}

转驼峰

var str = 'background-color'
var pattern = /-([a-z])/gi
console.log(str.replace(pattern,function(all,letter){
    return letter.toUpperCase()
}))	//'backgroundColor'

封装成一个函数

   function toCamelCase(str){
       return str.replace(pattern,function(all,letter){
           return letter.toUpperCase()
       })
   }

匹配HTML标签

var str = '<p class="odd" id="odd">123</p>'
var  pattern =  /<\/?[a-zA-Z]+(\s+[a-zA-Z]+=".*")*>/g
console.log(pattern.match(pattern))

逆向思考一下

var str = '<p class="odd" id="odd">123</p>'
var  pattern =  /<[^>]+>/g
console.log(pattern.match(pattern))

上述的可能会存在一些问题,比如如果双引号里有 > 这个符号,就会出现匹配错误的现象,我们进行完善,代码如下:

var str = '<input type="text" value=">" name="username" />';
var pattern = /<(?:[^"'>]|"[^"]*"|'[^']*')*>/g;
console.log(str.match(pattern));
var str = '<input type="text" value=">" name="username" />';
var pattern = /<(?:[^"'>]|(["'])[^"']*\1)*>/g;
console.log(str.match(pattern));

邮箱验证

例如:fang.123456.com

第一种方式

var pattern = /(?:\w+\.)*\w+@(?:\w+\.)+[a-z]/i

第二种方式

var pattern = /^[a-z0-9]+(?:[._-][a-z0-9]+)*@[a-z0-9]+(?:[._-][a-z0-9]+)*\.[a-z]{2,4}$/i
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值