正则表达式
用来匹配符合某种规则的字符串
案例
- 检索字符串中符合某种规则多个子字符串
- 判断用户的输入是否符合某种规则
- 替换字符串中符合某种规则的文本
- 用户输入的是不是合法的手机号
- 用户输入的是不是合法的邮箱
- 用户输入的是不是合法的用户名
创建方式
字面量的方式创建——//
[]
{}
//
这些都属于字面量
构造函数的方式创建
如果正则表达式将会改变,或者它将会从用户输入等来源中动态地产生,就需要使用构造函数来创建正则表达式。
转义
遇到特殊的字符或者能组成特殊字符的,进行转义操作;其他情况相当于不存在
如果将RegExp构造函数与字符串文字一起使用,请记住反斜杠是字符串文字中的转义,因此要在正则表达式中使用它,您需要在字符串文字级别转义它。 /a*b/ 和new RegExp("a\b")创建的表达式是相同的,搜索“a”后跟文字“”后跟“b”。
new RegExp('+86\d{11}','g')
前面代表字符串,后面代表匹配的模式
修饰符
-
g
——global全文搜索,不添加的话,搜索到第一个就停止 -
i
——ignore case忽略大小写,默认大小写敏感 -
m
——multiple lines多行搜索
正则的方法
reg.test(str)
var reg = /\+86\d{11}/
reg.test("+861302030304005030403")
reg.test("+8613020303040")
reg.test("+8613020303040a")
false
true
false
reg.exec(str)
字符串的方法参数可以是正则表达式
str.search(reg)
str.match(reg)
str.replace(reg)
str.replace(/str(reg)/g, 'str$1')
str.replace(reg, function(matched, $1, index) { })
str.split(reg)
let str = 'hello1 Ryan, hello2 world'
str.search(/hello\d/)
str.match(/hello\d/g)
str.replace(/hello\d/g, 'hi')
str.split(/\s/)
str.split(/\d/)
0
["hello1", "hello2"]
"hi Ryan, hi world"
["hello1", "Ryan,", "hello2", "world"]
["hello", " Ryan, hello", " world"]
上述字符串方法,没有改变原字符串
专用字符
匹配有特殊意义的字符,需要转义
\
(
)
[
]
{
}
\
^
$
|
?
*
+
.
范围匹配
[]
代表匹配一个字符
[abcd]
匹配一个字符,是a b c d中的任意一个
[0-9]
匹配一个是0到9的数字
[a-zA-Z]
匹配一个不限制大小写的字母
[^abc]
匹配不是a b c的字符
let reg = /不要[89][89][67]/
reg.test('我们不要996')
reg.test('我们要965')
true
false
合法变量名????中文?
/[_$a-zA-Z][_$a-zA-Z]*/
预定义匹配——固定的匹配
-
.
等价于 [^\r\n],匹配一个除回车和换行以为的任意字符 -
\d
等价于[0-9],匹配一个数字字符 -
\D
等价于[^0-9], 匹配一个非数字字符 -
\s
等价于[\t\n\r\v\f],匹配一个空白字符 -
\S
等价于[^\t\n\r\v\f],匹配一个非空白字符 -
\w
等价于[a-zA-Z_0-9],匹配一个字母、数字、下划线 -
\W
等价于[^a-zA-Z_0-9],匹配一个非单词字符
量词——匹配字符串的相加操作
-
?
前面的字符出现0次或者1次 -
+
前面的字符出现1次或者多次 -
*
前面的字符出现0次或者多次 -
{n}
前面的字符出现n次,无空格 -
{n,m}
前面的字符出现n到m次,无空格 -
{n,}
前面的字符出现至少n次,无空格
边界
-
/^xyz/
以xyz开头 -
/abc$/
以abc结尾 -
/\babc\b/
匹配是单词的abc(左右两侧是字符串开头、 结尾、中横线、空格) -
/\Babc\B/
匹配不是单词的abc
获取一篇文章单词的数量????
var str2 = 'hello1 whello9orld hello2 12-hello8-3456 jirengu ruoyu hello3'
str2.match(/\b\w+\d\b/g)
12-hello8-3456
是一个单词,但是被分开
不要自以为是,因为自己有限的认知,让用户无法使用
匹配手机号
/^1\d{10}$/
/^(\+86)?1\d{10}$/
是为了防止用户误操作,不是越严格越好
匹配邮箱
规则:字符串中间包含一个
@
,@后面包含个.
只需要简单的限制,目的是防止用户误操作,收不到邮箱是他的事,不能隔离有用的邮箱
let reg = /^[^@\s]+@[^@\s]+\.[^@\s]+$/
匹配用户名
规则:合法用户名至少8位至多15位,包含大写、小写、 数字、下划线至少两种
规则太难,可以把不符合条件的返回错误,符合条件的留下来
function validUsername(rawInput) {
if (!/^\w{8,15}$/.test(rawInput)) return false
if (/(^[a-z]+$)|(^[A-Z]+$)|(^[0-9]+$)|(^\d+$)|(^_+$)/.test(rawInput)) return false
}
写正则表达式不是目的,解决问题,让别人明白才是重点
贪婪模式和非贪婪模式
'123456789'.match(/\d{3,5}/g)
的结果是什么?
["12345", "6789"]
默认是贪婪模式,即可能多的匹配
非贪婪模式
量词后加
?
,尽可能少的匹配
'123456789'.match(/\d{3,5}?/g)
``aa"hello world" ok "Ryan".match(/".+?"/g)
分组
把一些字符用
()
当做一个整体;使用$n
代表第n分组匹配的内容
/hunger{3}/
匹配'hungerrr'
/(hunger){3}/
匹配'hungerhungerhunger'
(hello)|(hi) wolrd/
匹配'hello world'
和'hi world'
`"hello8 world, hello6 Ryan".replace(/hello(\d)/g, 'hi$1')`
'hi8 world, hi6 Ryan'
'<div>this is a div</div>'.replace(/(<\/?)div(>)/g,'$1span$1')
"<span<this is a div</span</"
'<div>this is a div</div>'.replace(/(<\/?)div(>)/g,'$1span$2')
"<span>this is a div</span>"
'<div>this is a div</div>'.replace(/<div>/,'<span>').replace(/<\/div>/,'</span>')
"<span>this is a div</span>"
前瞻
exp1(?=exp2)
后面是exp2的exp1
exp1(!=exp2)
后面不是exp2的exp1
RegExp.prototype.exec
调用全局的RegExp对象的exec()时,它会在RegExp实例的 lastIndex属性指定的字符处开始检索字符串string
当exec()找到了与表达式相匹配的文本时,在匹配后,它将把RegExp实例的lastIndex属性设置 为匹配文本的最后一个字符的下一个位置。可以通过反复调用exec()方法来遍历字符串中的所有匹配文本
当 exec() 再也找不到匹配的文本时,它将返回null,并把lastIndex属性重置为0
let reg = /\b\w+\b/g, temp
while(temp = reg.exec('hello world, hi jirengu')) {
console.log(`${temp.index} : ${temp[0]}`)
}
/*输出 0 : hello 6 : world 13 : hello 19 : jirengu */
String.prototype.replace(reg, function)
第二个参数传入一个function,会在每次匹配替换的时候调用, 返回值为要替换的内容,回调函数一共有3/4个参数
- 第一个参数很简单,是匹配字符串
- 第二个参数是正则表达式分组内容,若没有分组则没有该参数
- 第三个参数是匹配项在字符串中的index,若没有分组该为第二个参数
- 第四个参数则是原字符串,若没有分组该为第三个参数
把字符串转换成驼峰形式
let str = 'border-top-color'
const strToCamel = str => str.replace(/-(\w)/g, (match, $1) => $1.toUpperCase())
console.log( strToCamel(str) )