概念
正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式(规则),是由普通字符(比如a-z字母)和特殊字符(也称元字符)组成
正则表达式用途
- 【检索】匹配数据格式(比如,登录、注册时的格式校验)
- 【替换】替换文本内容(比如,对一些非法字符的替换等)
- 【提取】从字符串中提取我们要的特定部分(比如,截取URL域名或者参数)
RegExp语法
- 通过构造函数的方式创建正则表达式对象:
const reg = new RegExp("pattern", modifiers)
一般会用在正则匹配主体不确定的情况下使用 - 利用字面量创建正则表达式对象:
const reg = /pattern/modifiers
这种写法比较常用
RegExp的对象方法
- compile:编译正则表达式 1.5版本已废除
- exec:检索字符串中指定的值,返回找到的值,确定其位置
- test:检索字符串中是否存在指定的值,返回true或false
- toString:返回正则表达式的字符串
RegExp对象方法使用姿势
test 这个是比较常用的方法,判断是否符合匹配模式的都可以用这个方法,比如表单格式校验、是否包含指定非法字符等
比如
# 如果是全局匹配的话,会在每次匹配完更改lastIndex值
var reg = /lucky/g
reg.test('I am lucky boy') // 返回true
# lastIndex变化例子
var a = /ab/g
var str = 'kkabkkabkk'
a.test(str) // 此时匹配到的是第一个ab,返回true
a.lastIndex // 4
a.test(str) // 此时匹配到的是第二个ab,返回true
a.lastIndex // 8
a.test(str) // 此时lastIndex为8,往后已经匹配不到了,返回false
a.lastIndex // 0,被重置为初始值
a.test(str) // 此时又开始从头开始匹配,返回0
exec 检索字符串中的指定值,返回的是被找到的值(一个数组),如果没有匹配到,则返回null
const reg = /chen/
reg.exec('My name is chenjiaobin')
# return ["chen", index: 11, input: "My name is chenjiaobin", groups: undefined]
- 元素0 表示与正则表达式相匹配的文本
- 元素1 表示与第一个子表达式
reg = /(partten)/
相匹配的文本,如果有多个,以此类推,元素3、4...
// 两个子表达式的正则,最后返回的结果的下标1和下标2的值分别对应子表达式匹配到的值
const reg = /(chen)(jiao)/
reg.exec('My name is chenjiaobin')
// 返回 ["chenjiao", "chen", "jiao", index: 11, input: "My name is chenjiaobin", groups: undefined]
- index元素则是匹配文本的第一个字符的位置
- input匹配的则是被检索的字符串
- group是用来存储命名捕获组的信息,只有捕获组使用命名的时候才会有值,比如,
# ?<first>就是为捕获组设置别名
const reg = /(?<first>chen)/
reg.exec('My name is chenjiaobin')
# return ["chen", "chen", index: 11, input: "My name is chenjiaobin", groups: { first: 'chen' }]
- 当设置正则表达式为全局的时候,会在RegExp的lastIndex属性指定的字符开始检索字符串,
当匹配到对应文本后,RegExp的lastIndex属性会重新被设置为匹配文本的最后一个字符的下一个位置下标,直到被匹配文本没有可以被匹配的文本,返回null,且lastindex被重置为0,因此,当我们需要反复使用同一个正则表达式的时候,在匹配新的字符串之前重置lastIndex为0;或者不把实例化好的正则实例赋值给变量,而是直接使用/partern/.exec('abcd')
var reg = /a/g
reg.exec('abcdabcdabcd') # 第一次 return ["a", index: 0, input: "abcdabcdabcd", groups: undefined]
reg.exec('abcdabcdabcd') # 第二次 return ["a", index: 4, input: "abcdabcdabcd", groups: undefined]
reg.exec('abcdabcdabcd') # 第三次 return ["a", index: 8, input: "abcdabcdabcd", groups: undefined]
reg.exec('abcdabcdabcd') # 第四次 return null
# 没有全局修饰符g
var reg = /a/
reg.exec('abcdabcdabcd') # 始终返回 ["a", index: 0, input: "abcdabcdabcd", groups: undefined]
# exec如果不是全局模式的话,跟match返回的是一样的
# match如果是全局模式的话,会一次性返回结果,比如
'abcdabcdabcd'.match(/a/g) // return ['a', 'a', 'a']
支持正则表达式的String对象的方法
- search:检索与正则表达式匹配的值
- match:找到一个或多个正则表达式的匹配
- replace:替换与正则表达式匹配的字符串(不改变原始字符串)
- split:分割字符串为字符串数组(不改变原始字符串)
String对象方法使用姿势
search
string.search(searchValue)
# searchValue可以是字符串或者是正则表达式,如果匹配的上就返回第一个的下标,否则返回-1
match
该方法的行为很大程度依赖于是否是全局模式,匹配不到返回null
# 非全局,只匹配了一次,返回的结果跟exec一样
var reg = /chen/
'chenjiaochen'.match(reg)
# 返回 ["chen", index: 0, input: "chenjiaochen", groups: undefined]
# 全局
var reg = /chen/g
'chenjiaochen'.match(reg)
# 返回 ["chen", "chen"]
replace
string.replace(separator, str|fn)
// 第二个参数可以是字符串或者是匿名函数,匿名可以让我们对匹配到的字符串为所欲为的改动,比如
const str = '他今年22岁,她今年20岁,他的父亲今年40岁,她的父亲今年45岁,总共有4个人'
const reg = /(\d+)岁/g
// 第一个参数表示匹配到的字符,第二个参数表示匹配时的字符最小索引位置(RegExp.index),第三个参数表示被匹配的字符串(RegExp.input),实际上参数的个数是不确定的,会随着子匹配的变多而变多
function formatAge (a, b, d) {
const year = (new Date()).getFullYear()-parseInt(a)-1
return a + '(' + year + '年出生)'
}
str.replace(reg, formatAge)
// return "他今年22岁(1998年出生),她今年20岁(2000年出生),他的父亲今年40岁(1980年出生),她的父亲今年45岁(1975年出生),总共有4个人"
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, function(match, year, month, day) {
return month + "/" + day + "/" + year;
});
console.log(result);
// => "06/12/2017"
split
string.split(separator, limit)
# 第一个参数为指定分割符,可以是字符串或正则表达式,第二个参数指定返回的数组的最大长度
修饰符
修饰符 | 含义 | 描述 | i | ignore-不区分大小写 | 设置匹配字符不区分大小写,A和a没区别 | g | global-全局匹配 | 查找所有匹配项(注:使用的时候要注意lastIndex是否被重置的问题) | m | multiline-多行匹配 | 使边界字符^和$匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾 | s | 特殊字符原点(.)中包含换行字符 \n | 默认情况下圆点匹配换行字符\n之外的任何字符,加上s修饰符后,则(.)中包含换行符 \n |
---|
m 多行匹配例子:
const str = 'abc\nabc\nabc'
str.match(/^abc/g) // return ['abc'] 只返回了一个匹配值,因为其他两个都换行了
str.match(/^abc/gm) // return ['abc', 'abc', 'abc'] 修饰符添加了个多行匹配
s 修饰符例子:
const str = 'bei\nzuo\nsi'
str.match(/bei./) // return null 没有匹配到任何数据,返回了null
str.match(/bei./s) // return ['bei', ......] 匹配到了一个字符串,返回了一个数组
元字符(常用)
字符 | 描述 | \ | 将下一字符标记为一个特殊字符或原意字符,比如\n表示一个换行字符 | ^ | 匹配输入字符串的开始位置,如果设置了multiline属性,^ 也匹配\n或\r之后的位置,如'abc\nab'.match(/^ab/gm)',返回['ab','ab'],如果没有m则返回['ab'] | $ | 匹配字符串的末尾,如果设置了multiline属性,$也匹配\n或\r之前的位置 | * | 匹配前面的子表达式0次或多次,如zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,} | + | 匹配前面的指标是是一次或多次,如'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,} | ? | 匹配前面的子表达式0次或1次,如"do(es)?" 可以匹配 "do" 或 "does" 。? 等价于 {0,1} | {n} | n是一个非负整数,匹配确定的n次,如'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o | {n,} | 匹配至少n次,如'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*' | [xyz] | 字符集合,匹配所包含的任意字符,[up]可以匹配lucky中的u | [^xyz] | 跟[xyz]相反,匹配未包含集合的任意字符,如[up]可以匹配lucky中的l c k y | [a-z] | 匹配字符范围,匹配指定范围内的任意字符,当然也可以[a-c]这种 | [^a-z] | 跟[a-z]相反 | \b | 匹配单词边界,也就是单词和空格间的位置,如er\b可以匹配nerver中的er,也可以匹配'aer b'的er,不能匹配verb中的er | \B | 匹配非单词边界,'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er' | \d(\D相反) | 匹配一个数字字符,等价于[0-9] | \s(\S相反) | 匹配任何空白字符,包括空格、制表符、换页符等,等价于[\f\n\r\t\v] | \w(\W相反) | 匹配字母、数字、下划线,等价于[A-Za-z0-9_] | (pattern) | 分组捕获,匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 0…9 属性。要匹配圆括号字符,请使用 '(' 或 ')'。 | . | 匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括\n在内的任何字符,可以使用`. |
---|
拓展解释
- ?:如果该字符跟在其他限制符( *, +, ?, {n}, {n,}, {n,m} )后面时,匹配模式是非贪婪的,即会尽可能少的匹配所搜索的字符串,而默认的贪婪模式则时尽可能多的匹配内容,如ooo,'o+?'只会匹配单个'o',而'o+'将匹配所有'o'
- 对一些特殊字符($、()、*、+、. 、[、? 、\、^、{ 、|),如果要匹配他们需要在他们前面添加转义符 \n
+ 和 *
都是贪婪的,它们会可能多的匹配文字,我们可以通过在他们后面加上一个 ? 就能实现非贪婪或最小匹配。比如:匹配 我滴个神哦,正则为/<.*>/
,那么匹配出来的是整个字符串,如果正则为/<.*?>/,那么匹配出来的就只是前面的- 圆括号( )表示捕获分组,它会把分组里匹配的值保存起来。我们可以利用这个临时缓存,通过\n的方式表示特定匹配内容,比如/([a-z]+)abc\1/这样通过\1来代替再一次写([a-z]+)这一个规则。但用圆括号会有一个副作用,会使相关的匹配被缓存,此时可以用 ?: 放在第一个选项前来消除这种副作用。
var reg = /(chen)jiaobin(kevin)/
'chenjiaobinkevinkk'.replace(reg, '$1测试$2')
# 返回:chen测试kevinkk($1获取到的是chen,$2获取到的是kevin)
# 使用?:消除圆括号带来的缓存
var reg = /(?:chen)jiaobin(kevin)/
'chenjiaobinkevinkk'.replace(reg, '$1测试$2')
# 返回:kevin测试$2kk
# 因为第一个圆括号的缓存被消除了,所以$1获取到的是kevin,$2获取不到被当成字符串输出
# 如果要$1和$2都失效那么就都在前面添加?:符号
# 加了?:符号后替换符号\1等也失效
'chenjiaobinchenkk'.match(/(chen)jiaobin\1/)
# 返回 ["chenjiaobinchen", "chen", index: 0, input: "chenjiaobinchenkk", groups: undefined]
# 此时匹配中的\1代表的是chen这个字符串,整个正则同等`/(chen)jiaobinchen/`
'chenjiaobinchenkk'.match(/(?:chen)jiaobin\1/)
# 返回的是null,此时被消除了缓存,\1表示的就是自己
-
- exp1(?=exp2):查找exp2前面的exp1 (比如'ageoldageyear'.match(/age(?=year)/,匹配到的是后面的)
- (?<=exp2)exp1:查找exp2后面的exp1
- exp1(?!exp2):查找后面不是exp2的exp1
- (?<!exp2)exp1:查找前面不是exp2的exp1
运算符优先级
以下优先级上到下是高到低排序
\ :转义符
() (?:) (?=) [] :圆括号和方括号
*, +, ?, {n}, {n,}, {n,m}: 限定符
^, $, \任何元字符、任何字符 : 定位点
| :或操作
优先级问题一般比较少见,不过还是需要了解下,比如 m|food 会匹配出m或者food,而不是mood或food,因为字符的比较优先级大于”或“操作,可以这样改(m|f)ood就没问题了
常用正则场景匹配规则
汉字:^[\u4e00-\u9fa5]{0,}$
身份证(15或18或17+校验位X x):(^\d{15})|(^\d{18})|(^\d{17}(\d|X|x)$)
邮箱校验:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
手机号码:^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$
正则校验查看器
- Regulex:jex.im/regulex/#!f… (推荐)
- 菜鸟工具:c.runoob.com/front-end/8…
正则相关文章
- 菜鸟教程:www.runoob.com/regexp/rege…
- CSDN文章:blog.csdn.net/whitegay/ar…
- RegExp对象和支持正则的String方法:www.runoob.com/jsref/jsref…
- 掘金(老姚):juejin.cn/post/684490…
- 正则表达式电子书下载
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!