shaozj / blog

blog
87 stars 4 forks source link

javascript 正则表达式解析 #26

Open shaozj opened 5 years ago

shaozj commented 5 years ago

javascript 正则表达式解析

在日常开发中,正则表达式常常能让人很困惑。实际上,掌握好正则表达式能让你的开发大大提效。废话不多说,直接开始学习吧。

什么是正则表达式

正则表达式是用于匹配字符串中字符组合的模式。大部分语言都实现了正则表达式,而我们要研究的是 javascript 中的正则表达式。

创建一个正则表达式

有两种方式可以创建正则表达式:

使用正则表达式字面量创建

语法:/pattern/[flags]

const re = /ab+c/;
re.test('abbbc'); // true

flags 是可选的,将在下文中解释。

使用 RegExp 对象的构造函数创建

语法:new RegExp(pattern[, flags])

const re = new RegExp('ab+c');
re.test('abc'); //true

无论使用字面量的方式还是构造函数的方式,得到的都是正则表达式对象。

正则表达式的方法

正则表达式主要有两个方法:

RegExp.prototype.test()

test 方法用于测试字符串是否匹配正则表达式,它返回 true 或者 false。例子:

const re = /hello/;
re.test('hello world'); // true
re.test('hell0 world'); // false

RegExp.prototype.exec()

exec 方法用于在一个在字符串中执行查找匹配的RegExp,它返回一个数组(未匹配到则返回 null)。 exec 方法匹配成功后将返回一个数组并且更新正则表达式的属性。
先看一个例子:

const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");
// ["dbbd", "bb", index: 1, input: "cdbbdbsbz", groups: undefined]

返回的数组

属性或索引 描述 在例子中对应的值
匹配到的字符串和所有被记住的子字符串。 ["dbbd", "bb"]
index 在输入的字符串中匹配到的以0开始的索引值 1
input 初始字符串。 "cdbbdbsbz"
groups 捕获组 看下面例子
// 命名捕获组的获取
let reg1 = /(?<first>\d)(?<second>\d)/;
let str2 = '123';

console.log(reg2.exec(str2).groups);
// => { first: 1, second: 2 } 而新的语法支持对这些捕获组进行命名,
// 更方便地获取某个捕获组的数据

更新正则表达式属性

属性或索引 描述 在例子中对应的值
lastIndex 下一个匹配的索引值。(这个属性只有在使用g参数时可用在) 5
source 模式文本。在正则表达式创建时更新,不执行。 "d(b+)d"

正则表达式的模式

简单模式

简单模式是由你想直接找到的字符构成。比如,/abc/ 这个模式就能且仅能匹配 "abc" 字符按照顺序同时出现的情况。

const regex = /hello/;
console.log(regex.test('hello world')); // true

使用特殊字符

当你需要搜索一个比直接匹配需要更多条件的匹配时,比如寻找一个或多个 "b",或者寻找空格,这时可以在模式中使用特殊字符。比如,你可以使用 /ab*c/ 去匹配一个单独的 "a" 后面跟了零个或者多个 "b",同时后面跟着 "c" 的字符串:*的意思是前一项出现零次或者多次。在字符串 "cbbabbbbcdebc" 中,这个模式匹配了子字符串 "abbbbc"。

下面列出了一个正则表达式中可以利用的特殊字符的完整列表和描述。

标识 flags

两个最重要的标识:

const re = /\w+\s/g;
const str = "fee fi fo fum";
console.log(str.match(re)); // ["fee ", "fi ", "fo "]
const re1 = /\w+\s/;
console.log(str.match(re1)); 
// ["fee ", index: 0, input: "fee fi fo fum", groups: undefined]

注意上面例子中的 String.prototype.match 方法,当正则表达式带有 g 这个标识的时候,它返回的是所有匹配项组成的数组。如果正则表达式没有 g 这个标识,那么返回结果和 regexp 的 exec 方法一致。

const re = /abc/i;
console.log(re.test('Abc')); // true

字符类别(Character Classes)

区分不同类型的字符,例如区分字母和数字。

组和范围(Groups and Ranges)

表示表达式字符的分组和范围。

量词(Quantifiers)

表示匹配的字符或表达式的数量。

边界(Boundaries)

表示行和单词的开始和结尾。

断言(Assertions)

表示一个匹配在某些条件下发生。断言包含先行断言、后行断言和条件表达式。

Unicode 属性转义(Unicode Property Escapes)

基于 unicode 字符属性区分字符。例如大写和小写字母、数学符号和标点。

例子

'1234567'.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// 1,234,567

用到了非单词边界、先行断言、正向否定查找、匹配数字、量词

/<span\b[^>]*>(.*?)<\/span>/

/<span\b[^>]*>(.*?)<\/span>/.exec('test')
// null
/<span\b[^>]*>(.*?)<\/span>/.exec('<span>test</span>')
// ["<span>test</span>", "test"]
/<span\b[^>]*>(.*?)<\/span>/.exec('<span class="x">test</span>')
// ["<span class="x">test</span>", "test"]

参考文献: