正则表达式的模式匹配

正则表达式是一个描述字符模式的对象。JavaScript 的 RegExp 类表示正则表达式,String 和 RegExp 都定义了方法,后者使用正则表达式进行强大的模式匹配和文本检索与替换功能。

正则表达式的定义
正则表达式可以使用 RegExp() 构造函数来创建 RegExp 对象,更多的是通过一种特殊的直接量语法来创建。

var pattern = new RegExp('s$');
var pattern = / s$ /;

RegExp对象

RegExp() 构造函数带有两个字符串参数,其中第二个参数是可选的,RegExp() 用以创建新的 RegExp 对象。第一个参数包含正则表达式的主体部分,也就是正则表达式直接量中两条斜线之间的文本。RegExp() 的第二个参数是可选的,如果提供第二个参数,它就指定正则表达式的修饰符。

let zipCode = new RegExp('\\d{5}', 'g');

RegExp的属性:

  1. 属性 source 是一个只读的字符串,包含正则表达式的文本。
  2. 属性 global 是一个只读的布尔值,用以说明这个正则表达式是否带有修饰符 g 。
  3. ignoreCase 也是一个只读的布尔值,用以说明是否带有修饰符 i。
  4. multiline 是一个只读的布尔值,用以说明正则表达式是否带有修饰符 m。
  5. lastIndex 是一个可读/写的整数。

RegExp的方法:

1. test

它的参数是一个字符串,用 test() 对某个字符串进行检测,如果包含正则表达式的一个匹配结果,则返回 true。

let pattern = /java/i;
pattern.test('JavaScript'); //true

let pattern = /java/ig;
pattern.test('JavaScript'); //true

let pattern = /java/ig;
pattern.test('JavaScript JavaScript'); //true

2. exec

let pattern = /Java/;
let text = 'JavaScript is more fun than Java!';
console.log(pattern.exec(text));
console.log('lastIndex ', pattern.lastIndex);
//['Java', index: 0, input: 'JavaScript is more fun than Java!]
//lastIndex 0

let pattern = /Java/g;
let text = 'JavaScript is more fun than Java!';
let result;
while( (result = pattern.exec(text)) !== null){
	console.log(result);
	console.log('lastIndex ', pattern.lastIndex);
}
// ['Java', index:0, input: 'JavaScript is more fun than Java!']
//lastIndex 4
// ['Java', index:28, input: 'JavaScript is more fun than Java!']
//lastIndex 32

用于模式匹配的 String 方法

1. search

它的参数是一个正则表达式,返回第一个与之匹配的子串的起始位置,如果找不到匹配的子串,它将返回 -1。如果 search() 的参数不是正则表达式,则首先会通过 RegExp 构造函数将它转换成正则表达式,search 方法不支持全局搜索,因为它忽略正则表达式参数中的修饰符 g。

console.log('JavaScript'.search(/javascript/i)); //0
console.log('JavaScript'.search(/script/i)); //4

console.log('JavaScript'.search('javascript')); //-1
console.log('JavaScript'.search('script')); //-1
console.log('JavaScript'.search('JavaScript')); //0
console.log('JavaScript'.search('Script')); //4

2. replace

replace() 方法用以执行检索和替换操作。其中第一个参数是一个正则表达式,第二个参数是要进行替换的字符串。这个方法会对调用它的字符串进行检索,使用指定的模式来匹配。如果 replace() 第一个参数是字符串而不是正则表达式,则 replace() 将直接搜索这个字符串。

console.log('JavaScript javascript'.replace(/javascript/gi, 'JavaScript')); //JavaScript JavaScript
console.log('JavaScript javascript'.replace(/javascript/i, 'JavaScript')); //JavaScript javascript

console.log('JavaScript javascript'.replace('javascript', 'JavaScript')); //JavaScript Javascript
console.log('javascript javascript'.replace('javascript', 'JavaScript')); //JavaScript javascript

3. match

它的唯一参数就是一个正则表达式(或通过 RegExp() 构造函数将其转换为正则表达式),返回的是一个由匹配结果组成的数组。

如果 match() 执行的不是全局检索,在这种情况下,数组的第一个元素就是匹配的字符串,余下的元素则是正则表达式中用圆括号括起来的子表达式。除了这些常规数组元素,这个返回的数组还有两个额外的对象属性。其中 index 属性指明了匹配文本在字符串中的开始位置;input属性则是对该字符串的引用。

console.log('1 plus 2 equals 3'.match(/\d+/));// [1, index: 0, input: '1 plus 2 equals 3']
console.log('1 plus 2 equals 3'.match(/\d+/g));// [1, 2, 3]

console.log('111 plus 21 equals 31'.match(/(\d)+\1/));// [111, index: 0, input: '111 plus 21 equals 31']
console.log('111 plus 21 equals 31'.match(/(\d)+\1/g));// [111]
console.log('111 plus 11 equals 11'.match(/(\d)+\1/g));// [111, 11, 11]

注意对于全局匹配,match() 不会提供关于圆括号子表达式的信息,也不会有 index, input 属性。如果希望在全局搜索时取得这些信息,可以使用 RegExp.exec()。

4. split
将一个字符串切分为一个由字符串组成的数组。split() 接收两个参数,第一个参数为切分处的字符串或正则表达式(分隔符),第二个为可选参数,指定返回数组的最大长度。

split() 方法返回的数组的元素是这样创建的:从字符串的开头搜索到结尾,在所有匹配 分隔符的文本的前方及后方断开。

1.如果分隔符匹配给定字符串的开头内容,则返回数组的第一个元素将是空字符串。类似地,如果分隔符匹配改字符串的末尾,则返回数组的最后一个元素将是空字符串。
2.如果没有指定分隔符的,则字符串将不会切分,返回的数组将只包含一个未切分的字符串元素。
3.如果分隔符为空字符串或是一个匹配空字符串的正则表达式,则字符串将在每个字符之间断开。
4.split() 方法返回的数组中的子串不包含用来切分改字符串的分隔文本。不过,如果分隔符是一个圆括号表达式的正则表达式,则匹配这些圆括号表达式的子串将包含在返回的数组中。

console.log('1:2:3:4:5'.split(':'));//['1','2','3','4','5']
console.log('1:2:3:4:5'.split(':', 3));//['1','2','3']

//1
console.log(':1:2:3:4:5'.split(':'));//['','1','2','3','4','5']
console.log('1:2:3:4:5:'.split(':'));//['1','2','3','4','5','']
//2
console.log('1:2:3:4:5'.split());//['1:2:3:4:5']
console.log('1:2:3:4:5'.split(' '));//['1:2:3:4:5']
console.log('1:2:3:4:5'.split(/\s+/));//['1:2:3:4:5']
//3
console.log('1:2:3:4:5'.split(''));//['','1','2','3','4','5']
//4
console.log('hello <b>world</b>'.split(/<[^>]*>/));// ['hello ', 'world', '']
console.log('hello <b>world</b>'.split(/(<[^>]*>)/));// ['hello ', '<b>', 'world', '</b>', '']

正则表达式中的所有字母和数字都是按照字面含义进行匹配的。JavaScript 正则表达式语法也支持非字母的字符匹配,这些字符需要通过反斜线(\)作为前缀转义。

1.直接量字符

表 1-1

字符匹配
字母和数字字符自身
\oNUL 字符(\u0000)
\t水平制表符(\u0009)
\v垂直制表符(\u000B)
\r回车符(\u000D)
\n换行符(\u000A)
\xnn由十六进制数 nn 指定的拉丁字符,例如,\x0A 等价于 \n
\uxxxx由十六进制数 xxxx 指定的 Unicode 字符,例如 \u0009 等价于 \t
\cX控制字符 ^X,例如,\cJ 等价于换行符 \n

2.字符类

将直接量字符单独放进方括号内就组成了字符类。一个字符类可以匹配它所包含的任意字符。

表 2-1

字符匹配
[…]方括号内的任意字符
[^…]不在方括号内的任意字符
.除换行符和其他 Unicode 行终止符之外的任意字符
\w任何 ASCII 字符组组成的单词,等价于 [ a-zA-Z0-9 ]
\W任何不是 ASCII 字符组成的单词,等价于 [ ^a-zA-Z0-9 ]
\s任何 Unicode 空白符
\S任何非 Unicode 空白符的字符,注意 \w 和 \S 不同
\d任何 ASCII 数字,等价于 [^0-9]
\D除了 ASCII 数字之外的任何字符,等价于 [^0-9]
[\b]退格直接量(特例)

重复字符语法

在正则模式之后跟随用以指定字符重复的标记。由于某些重复种类非常有用,因此就有一些专门用于表示这种情况的特殊字符。

表 3-1

字符含义
{n,m}匹配前一项至少 n 次,但不能超过 m 次
{n,}匹配前一项至少 n 次或者更多次
{n}匹配前一项 n 次
?匹配前一项 0 次或者 1 次,也就是说前一项是可选的,等价于 {0,1}
*匹配前一项 0 次或 多次,等价于 {0,}
+匹配前一项 1 次或 多次,等价于 {1,}

表 3-1 列出的匹配重复字符是尽可能多地匹配,而且允许后续的正则表达式继续匹配。因此,我们称之为 “贪婪的” 匹配。我们同样可以使用正则表达式进行非贪婪匹配。只须在待匹配的字符后跟随一个问号即可。

console.log('aaa'.match(/a+/)); ['aaa']
console.log('aaa'.match(/a+?/)); ['a']

console.log('aaab'.match(/a+b/)); ['aaab']
console.log('aaab'.match(/a+?b/)); ['aaab']

正则表达式的模式匹配总是会寻找字符串中第一个可能匹配的位置。 由于该匹配是从字符串第一个字符开始的,因此在这里不考虑它的子串更短的匹配。

选择、分组和引用字符
正则表达式的语法还包括指定选择项、子表达式分组和引用前一子表达式的特殊字符。

// |
console.log('ab'.match(/ab|cd|ef/)); // ['ab']
console.log('cd'.match(/ab|cd|ef/)); // ['cd']
console.log('ef'.match(/ab|cd|ef/)); // ['ef']
// (...) \n
console.log('ab'.match(/(ab|cd)+|ef/)); // ['ab', 'ab']
console.log('cd'.match(/(ab|cd)+|ef/)); // ['cd', 'cd']
console.log('ef'.match(/(ab|cd)+|ef/)); // ['ef']

console.log('abab'.match(/(ab|cd)+|ef\1/)); // ['abab']
console.log('cdab'.match(/(ab|cd)+|ef\1/)); // ['cdab', 'ab']
console.log('efab'.match(/(ab|cd)+|ef\1/)); // ['ef']
console.log('efab'.match(/(ab|cd)\1/)); // null

表 4-1

字符含义
|选择,匹配的是该符号左边的子表达式或右边的子表达式
(…)组合,将几个项组合为一个单元,这个单元可通过 ‘*’,‘+’,‘?’ 和 ‘|’ 等符号加以修饰,而且可以记住和这个组合相匹配的字符串以供此后的引用使用
(?:…)只组合,把项组合到一个单元,但不记忆与改组相匹配的字符
\n和第 n 个分组第一次匹配的字符相匹配,组是 圆括号 中的子表达式(也有可能是嵌套的),组索引是从左到右的左括号数,‘(?:’ 形式的分组不编码

指定匹配位置

像 \b 这样的元素不匹配某个可见字符,它们指定匹配发生的合法位置。有时我们称这些元素为正则表达式的锚,因为它们将模式定位在搜索字符串的特定位置上。

//(?=p)
console.log('JavaScript: The Definitive Guide'.match(/[Jj]ava([Ss]cript)?(?=\:)/)); //['JavaScript', 'Script']
console.log('JavaScript The Definitive Guide'.match(/[Jj]ava([Ss]cript)?(?=\:)/)); //null

//(?=p)
console.log('JavaScript'.match(/Java(?!Script)([A-Z]\w*)/)); // null
console.log('JavaScript'.match(/Java(?! Script)([A-Z]\w*)/)); // ['JavaScript', 'Script']
console.log('Java Script'.match(/Java(?! Script)([A-Z]\w*)/)); // null

表 5-1 正则表达式中的锚字符

字符含义
^匹配字符串的开头,在多行检索中,匹配一行的开头
$匹配字符串的结尾,在多行检索中,匹配一行的结尾
\b匹配一个单词的边界,简言之,就是位于字符 \w 和 \W 之间的位置,或位于字符 \w 和 字符串的开头或者结尾的位置(但需要注意,[\b] 匹配的是退格符)
\B匹配非单词边界的位置
(?=p)零宽 正向 先行断言,要求接下来的字符都与 p 匹配,但不能包含匹配 p 的那些字符
(?!p)零宽 负向 先行断言,要求接下来的字符不与 p 匹配

修饰符

正则表达式的修饰符,用以说明高级匹配模式的规则。修饰符是放在 / 符号之外的,也就是说,它们不是出现在两条斜线之间,而是第二条斜线之后。

字符含义
i执行不区分大小写的匹配
g执行一个全局匹配,简言之,即找到所有的匹配,而不是在找到第一个之后就停止
m多行匹配模式,^匹配一行的开头和字符串的开头,$匹配行的结束和字符串的结束

正则表达式实践

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值