正则表达式( Regular Expression )是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象。
正则表通常被用来检索、替换那些符合某个模式(规则)的文本。
例如验证表单:
其他语言也会使用正则表达式,作为前端萌新,这里我主要是利用JavaScript 正则表达式完成验证。
在 JavaScript 中,可以通过两种方式创建一个正则表达式。
方式一:通过调用RegExp对象的构造函数创建
var regexp = new RegExp(/Syoyu/);
console.log(regexp); // /Syoyu/
方式二:利用字面量创建
var rg = /Syoyu/;
test() 正则对象方法,用于检测字符串是否符合该规则,该对象会返回 true 或 false,其参数是测试字符串。
var rg = /Syoyu/;
console.log(rg.test(Syoyu));// 匹配字符中是否出现Syoyu 出现结果为true
console.log(rg.test('Syoyu'));// 匹配字符中是否出现Syoyu 未出现结果为false
一个正则表达式可以由简单的字符构成,比如 /abc/,也可以是简单和特殊字符的组合,比如 /ab*c/ 。其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如 ^ 、$ 、+ 等。
特殊字符非常多,可以参考:
MDN
jQuery 手册:正则表达式部分
正则测试工具
修饰符 | 说明 |
---|---|
i | 不区分大小写搜索 |
g | 全局搜索 |
m | 多行搜索 |
s | 允许 . 匹配换行符 |
u | 使用unicode码的模式进行匹配 |
y | 执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始 |
var reg = /pattern/flags // 使用方法
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
边界符 | 说明 |
---|---|
^ | 表示匹配行首的文本(以谁开始) |
$ | 表示匹配行尾的文本(以谁结束) |
如果 ^和 $ 在一起,表示必须是精确匹配。
var rg = /Syoyu/; // 正则表达式里面不需要加引号 不管是数字型还是字符串型
// /Syoyu/ 只要包含有Syoyu这个字符串返回的都是true
console.log(rg.test('Syoyu')) // true
console.log(rg.test('Syoyu1')) // true
console.log(rg.test('Syoyu2')) // true
var reg = /^Syoyu/; // 要求以Syoyu开头
console.log(reg.test('Syoyu')); // true
console.log(reg.test('Syoyu')); // true
console.log(reg.test('SSyoyu')); // false
var reg1 = /^Syoyu$/; // 精确匹配 要求必须是 Syoyu
console.log(reg1.test('Syoyu')); // true
console.log(reg1.test('Syoyuu')); // false
console.log(reg1.test('SSyoyuu')); // false
console.log(reg1.test('SyoyuSyoyu')); // false
字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内。
表示有一系列字符可供选择,只要匹配其中一个就可以了
var rg = /[abc]/; // 只要包含有a 或者 包含有b 或者包含有c 都返回为true
console.log(rg.test('andy'));//true
console.log(rg.test('baby'));//true
console.log(rg.test('color'));//true
console.log(rg.test('red'));//false
var rg1 = /^[abc]$/; // 三选一 只有是a 或者是 b 或者是c 这三个字母才返回 true
console.log(rg1.test('aa'));//false
console.log(rg1.test('a'));//true
console.log(rg1.test('b'));//true
console.log(rg1.test('c'));//true
console.log(rg1.test('abc'));//true
var reg = /^[a-z]$/ //26个英文字母任何一个字母返回 true - 表示的是a 到z 的范围
console.log(reg.test('a'));//true
console.log(reg.test('z'));//true
console.log(reg.test('A'));//false
//字符组合
var reg1 = /^[a-zA-Z0-9]$/; // 26个英文字母(大写和小写都可以)任何一个字母返回 true
//取反 方括号内部加上 ^ 表示取反,只要包含方括号内的字符,都返回 false 。
var reg2 = /^[^a-zA-Z0-9]$/;
console.log(reg2.test('a'));//false
console.log(reg2.test('B'));//false
console.log(reg2.test(8));//false
console.log(reg2.test('!'));//true
量词符用来设定某个模式出现的次数。
量词 | 说明 |
---|---|
* | 重复0次或更多次 |
+ | 重复1次或更多次 |
? | 重复0次或1次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
/^[a-zA-Z0-9_-]{6,16}$/ // 用户名只能为英文字母,数字,下划线或者短横线组成, 并且用户名长度为6~16位.
大括号 量词符. 里面表示重复次数
中括号 字符集合。匹配方括号中的任意字符.
小括号表示优先级
正则表达式在线测试
预定义类指的是某些常见模式的简写方式.
预定义类 | 说明 |
---|---|
\d | 匹配0-9的任一数字相当于[0-9] |
\D | 和\d相反, 匹配所有0-9以外的任一字符,相当于[^0-9] |
\w | 匹配任意的字母、数字和下划线,相当于[a-zA-Z0-9_] |
\W | 和\w相反,相当于[^a-zA-Z0-9_] |
\s | 匹配空格,相当于[\t\r\n\v\f] |
\S | 和\s相反,相当于[^\t\r\n\v\f] |
. | 查找单个字符,除了换行和行结束符 |
\b | 匹配单词边界。 |
\B | 匹配非单词边界。 |
\0 | 查找 NULL 字符。 |
\n | 查找换行符 |
\f | 查找换页符 |
\r | 查找回车符 |
\t | 查找制表符 |
\v | 查找垂直制表符 |
案例:验证座机号码
var reg = /^\d{3}-\d{8}|\d{4}-\d{7}$/;
var reg = /^\d{3,4}-\d{7,8}$/;
方法 | 说明 |
---|---|
exec | 对字符串进行查找匹配,返回一个数组(未匹配到返回null) |
test | 对字符串进行测试匹配,返回true或false |
replace | 替换与正则表达式匹配的子串,返回替换后的值,原始值不变 |
replaceAll | 替换与正则表达式匹配的所有子串,返回替换后的值,原始值不变。 注意: 当regexp是字符串时,匹配所有字串 当regexp是正则表达式时,必须加上g修饰符,否则会报错 |
match | 找到一个或多个正则表达式的匹配, 它返回一个数组,在未匹配到时会返回 null |
matchAll | 找到所有正则表达式的匹配, 它返回一个迭代器 注意:和replaceAll类似 |
search | 检索与正则表达式相匹配的值,返回首次检索到的值的下标 |
split | 把字符串分割为字符串数组 |
regexp.exec(str)方法返回匹配项
let str = 'Syoyu'
let regexp = /y/
regexp.exec(str) // ['y', index: 1, input: 'Syoyu', groups: undefined]
注意:
如果没有修饰符g,返回的就是匹配的第一项
如果有g修饰符,返回第一个匹配项,并将紧随其后的位置保存在regexp.lastIndex中。下一次调用会从regexp.lastIndex位置匹配,返回下一个匹配项…
let str = 'my name is Syoyu'
let regexp = /y/g
let result = null
while(result = regexp.exec(str)) {
console.log(result.index)
// 1
// 12
// 14
}
查找匹配项,然后返回 true/false 表示是否存在
let str = 'my name is Syoyu'
let regexp = /Syoyu/
let regexp1 = /syoyu/
regexp.test(str) // true
regexp1.test(str) // false
替换与正则表达式匹配的子串,返回替换后的值,原始值不变。在不设置全局匹配g的时候,只替换第一个匹配成功的字符串片段
let str = 'my name is Syoyu'
let regexp = /y/
let regexp1 = /y/g
str.replace(regexp, 'm') // mm name is Syoyu
str.replace(regexp1, 'm') // mm name is Smomu
console.log(str) // my name is Syoyu
替换与正则表达式匹配的所有子串,返回替换后的值,原始值不变。
当regexp是字符串时,匹配所有字串;当regexp是正则表达式时,必须加上g修饰符,否则会报错
let str = 'my name is Syoyu'
let regexp = /y/
let regexp1 = /y/g
str.replaceAll(regexp, 'm') // String.prototype.replaceAll called with a non-global RegExp argument
str.replaceAll(regexp1, 'm') // mm name is Smomu
str.replaceAll('y', 'm') // mm name is Smomu
console.log(str) // my name is Syoyu
找到一个或多个正则表达式的匹配, 它返回一个数组,在未匹配到时会返回 null
如果 regexp 不带有 g 标记,则它以数组的形式返回第一个匹配项
如果 regexp 带有 g 标记,则它将所有匹配项的数组作为字符串返回,而不包含分组和其他详细信息
let str = 'my name is Syoyu'
let regexp = /y/
let regexp1 = /y/g
str.match(regexp) // ['y', index: 1, input: 'my name is Syoyu', groups: undefined]
str.match(regexp1) // ['y', 'y', 'y']
str.macth(/b/) // null
返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。
当regexp是字符串时,匹配所有字串;当regexp是正则表达式时,必须加上g修饰符,否则会报错
let str = 'my name is Syoyu'
let regexp = /y/
let regexp1 = /y/g
str.matchAll(regexp, 'm') // String.prototype.replaceAll called with a non-global RegExp argument
str.matchAll(regexp1, 'm') // RegExpStringIterator {}
[...str.matchAll(regexp1, 'm')] // [Array(1), Array(1), Array(1)]
[...str.matchAll(regexp1, 'm')][0] // ['y', index: 1, input: 'my name is Syoyu', groups: undefined]
[...str.matchAll(regexp1, 'm')][1] // ['y', index: 12, input: 'my name is Syoyu', groups: undefined]
[...str.matchAll(regexp1, 'm')][2] // ['y', index: 14, input: 'my name is Syoyu', groups: undefined]
返回第一个匹配项的位置,如果未找到,则返回 -1
let str = 'my name is Syoyu'
let regexp = /y/
str.search(regexp) // 1 第一个匹配项的位置
使用正则表达式(或子字符串)作为分隔符来分割字符串
let str = 'my name is Syoyu'
let regexp = /\s/
str.search(regexp) // ['my', 'name', 'is', 'Syoyu']
匹配 | 说明 |
---|---|
贪婪匹配量词符 | *, +, ?, {n,}, {n, m} |
非贪婪匹配量词符 | *?, +?, ??, {n,}?, {n, m}? |
尽可能多的匹配,例如下面的列子
let regexp = /my{1,3}name/
在匹配的时候,尝试匹配的顺序是从多往少的方向去匹配的。首先尝试yyy,然后再看整个正则能否匹配上,如果不能匹配上,则开始尝试yy,以此往复。
如果多个贪婪量词挨在一起,则深度优先搜索
let str = 'my name is Syoyu'
let regexp = /(\D{1,5})(\D+)/
str.match(regexp)
// ['my name is Syoyu', 'my na', 'me is Syoyu', index: 0, input: 'my name is Syoyu', groups: undefined]
其中,\D{1,5} 匹配的是’my na’,\D+ 匹配的是’me is Syoyu’
惰性量词就是在贪婪量词后面加个问号,表示尽可能少的匹配
let str = 'my name is Syoyu'
let regexp = /(\D{1,5}?)(\D+?)/
str.match(regexp) // ['my', 'm', 'y', index: 0, input: 'my name is Syoyu', groups: undefined]
其中,\D{1,5}? 匹配的是 ‘m’,\D+? 匹配的是 'y’
分组主要是用过()进行实现,Syoyu{3},是匹配u字母3次。而(Syoyu){3}是匹配Syoyu三次
列入下面代码反向引用,巧用$分组捕获
let str = 'Syoyu'
let regexp = /(\D{1,2})(\D+)/
str.replace(regexp, '$2 $1') // 'oyu Sy'
上面代码中 Sy 和 oyu 交换了位置
元字符 | 说明 |
---|---|
(?:pattern) | 例如, 'industr(?:y|ies)‘就是一个比’industry|industries’ 更简略的表达式。 |
(?=pattern) | 正向肯定预查(look ahead positive assert)。 例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。 |
(?!pattern) | 正向否定预查(negative assert)。 例如,“Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows”。 |
(?<=pattern) | 反向(look behind)肯定预查。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。 |
(? | 反向否定预查。 例如"(? |
通过上面的内容,我们对正则表达式有了一定的了解
下面我们来看一看正则表达式的一些实际应用案列:
/^[a-zA-Z0-9_-]{4,16}$/
/^1[34578]\d{9}$/
/^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
}
function numFormat(num) {
return num.toString().replace(/\d+/, function(n) {
retrun n.replace(/(\d)(?=(\d{3})+$)/g, function($1) {
return $1 + ','
})
})
}