【JS】一文学会正则表达式

1.概述

1.1什么是正则表达式

正则表达式( Regular Expression )是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象。

正则表通常被用来检索、替换那些符合某个模式(规则)的文本。
例如验证表单:

  • 用户名表单只能输入英文字母、数字或者下划线,
  • 昵称输入框中可以输入中文(匹配)。
  • 正则表达式还常用于过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)。

其他语言也会使用正则表达式,作为前端萌新,这里我主要是利用JavaScript 正则表达式完成验证。

1.2 正则表达式的特点

  1. 灵活性、逻辑性和功能性非常的强。
  2. 可以迅速地用极简单的方式达到字符串的复杂控制。
  3. 对于刚接触的人来说,比较晦涩难懂。比如:/^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$/
  4. 实际开发,一般都是直接复制写好的正则表达式. 但是要求会使用正则表达式并且根据实际情况修改正则表达式. 比如用户名: /^[a-z0-9_-]{3,16}$/

2. 使用

2.1 创建

在 JavaScript 中,可以通过两种方式创建一个正则表达式。

方式一:通过调用RegExp对象的构造函数创建

var regexp = new RegExp(/Syoyu/);
console.log(regexp); // /Syoyu/

方式二:利用字面量创建

 var rg = /Syoyu/;

2.2 测试

test() 正则对象方法,用于检测字符串是否符合该规则,该对象会返回 true 或 false,其参数是测试字符串。

var rg = /Syoyu/;
console.log(rg.test(Syoyu));// 匹配字符中是否出现Syoyu  出现结果为true
console.log(rg.test('Syoyu'));// 匹配字符中是否出现Syoyu 未出现结果为false

3. 特殊字符

3.1 组成

一个正则表达式可以由简单的字符构成,比如 /abc/,也可以是简单和特殊字符的组合,比如 /ab*c/ 。其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如 ^ 、$ 、+ 等。

特殊字符非常多,可以参考:

MDN

jQuery 手册:正则表达式部分

正则测试工具

3.2 修饰符

修饰符 说明
i 不区分大小写搜索
g 全局搜索
m 多行搜索
s 允许 . 匹配换行符
u 使用unicode码的模式进行匹配
y 执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始
var reg = /pattern/flags // 使用方法

3.3 边界符

正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符

边界符 说明
^ 表示匹配行首的文本(以谁开始)
$ 表示匹配行尾的文本(以谁结束)

如果 ^和 $ 在一起,表示必须是精确匹配。

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

3.4 字符类

字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内。

3.4.1 [] 方括号

表示有一系列字符可供选择,只要匹配其中一个就可以了

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
3.4.2 量词符

量词符用来设定某个模式出现的次数。

量词 说明
* 重复0次或更多次
+ 重复1次或更多次
? 重复0次或1次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
/^[a-zA-Z0-9_-]{6,16}$/ // 用户名只能为英文字母,数字,下划线或者短横线组成, 并且用户名长度为6~16位.
3.4.3 括号总结
  1. 大括号 量词符. 里面表示重复次数

  2. 中括号 字符集合。匹配方括号中的任意字符.

  3. 小括号表示优先级

正则表达式在线测试

3.5 预定义类

预定义类指的是某些常见模式的简写方式.

预定义类 说明
\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}$/;

4. 匹配方法

方法 说明
exec 对字符串进行查找匹配,返回一个数组(未匹配到返回null)
test 对字符串进行测试匹配,返回true或false
replace 替换与正则表达式匹配的子串,返回替换后的值,原始值不变
replaceAll 替换与正则表达式匹配的所有子串,返回替换后的值,原始值不变。
注意: 当regexp是字符串时,匹配所有字串
当regexp是正则表达式时,必须加上g修饰符,否则会报错
match 找到一个或多个正则表达式的匹配, 它返回一个数组,在未匹配到时会返回 null
matchAll 找到所有正则表达式的匹配, 它返回一个迭代器
注意:和replaceAll类似
search 检索与正则表达式相匹配的值,返回首次检索到的值的下标
split 把字符串分割为字符串数组

4.1 regexp.exec(str)

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
}

4.2 regexp.test(str)

查找匹配项,然后返回 true/false 表示是否存在

let str = 'my name is Syoyu'
let regexp = /Syoyu/
let regexp1 = /syoyu/

regexp.test(str) // true
regexp1.test(str) // false

4.3 str.replace(regexp)

替换与正则表达式匹配的子串,返回替换后的值,原始值不变。在不设置全局匹配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

4.4 str.replaceAll(regexp)

替换与正则表达式匹配的所有子串,返回替换后的值,原始值不变。

当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

4.5 str.match(regexp)

找到一个或多个正则表达式的匹配, 它返回一个数组,在未匹配到时会返回 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

4.6 str.macthAll(regexp)

返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。

当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]

4.7 str.search(regexp)

返回第一个匹配项的位置,如果未找到,则返回 -1

let str = 'my name is Syoyu'
let regexp = /y/

str.search(regexp) // 1 第一个匹配项的位置

4.8 str.split(regexp)

使用正则表达式(或子字符串)作为分隔符来分割字符串

let str = 'my name is Syoyu'
let regexp = /\s/

str.search(regexp) // ['my', 'name', 'is', 'Syoyu']

5 几个常见的特性

5.1 贪婪模式和非贪婪匹配

匹配 说明
贪婪匹配量词符 *, +, ?, {n,}, {n, m}
非贪婪匹配量词符 *?, +?, ??, {n,}?, {n, m}?
(1). 贪婪模式

尽可能多的匹配,例如下面的列子

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’

(2). 非贪婪/懒惰模式

惰性量词就是在贪婪量词后面加个问号,表示尽可能少的匹配

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’

5.2 分组

分组主要是用过()进行实现,Syoyu{3},是匹配u字母3次。而(Syoyu){3}是匹配Syoyu三次

列入下面代码反向引用,巧用$分组捕获

let str = 'Syoyu'
let regexp = /(\D{1,2})(\D+)/
str.replace(regexp, '$2 $1') // 'oyu Sy'

上面代码中 Syoyu 交换了位置

5.3 一些特殊的元字符

元字符 说明
(?: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"。
(? 反向否定预查。 例如"(?

6 应用场景

通过上面的内容,我们对正则表达式有了一定的了解

下面我们来看一看正则表达式的一些实际应用案列:

6.1 用户名校验-4到16位(字母,数字,下划线,减号)
/^[a-zA-Z0-9_-]{4,16}$/
6.2 手机号
/^1[34578]\d{9}$/
6.3 URL
/^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
6.4 实现trim
String.prototype.trim = function() {
  return  this.replace(/^\s+|\s+$/g, '');
}
6.5 JavaScript实现千位分隔符
function numFormat(num) {
    return num.toString().replace(/\d+/, function(n) {
        retrun n.replace(/(\d)(?=(\d{3})+$)/g, function($1) {
            return $1 + ','
        })
    })
}

你可能感兴趣的:(javascript,javascript,正则表达式)