0

《JavaScript 权威指南》读书笔记 10 - 正则表达式的模式匹配

 5 months ago
source link: https://keelii.com/2016/07/06/javascript-definitive-guide-note-9/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

正则表达式(regular expression)是一个描述字符模式的对象。在 JavaScript 中 String 和 RegExp 都定义了相关方法对文本进行模式匹配、检索和替换

正则表达式的定义

JavaScript 中的正则表达式用 RegExp 对象表示,可以使用 RegExp() 构造函数来创建 RegExp 对象,不过也可以通过两个双斜杠「/reg/」以正则直接量的形式创建

var pattern = /s$/;             // 通过直接量创建
var pattern = new RegExp('s$'); // 通过构造函数创建

直接量字符

JavaScript 正则表达式语法也支持非字母的字符匹配,这些字符需要通过反斜线(\)作为前缀进行转义

表10-1

字符 匹配

字母和数字 自身

\0 NUL 字符(\u0000)

\t 制表符(\u0009)

\n 换行符(\u000A)

\v 垂直制表符(\u000B)

\f 换页符(\u000C)

\r 回车符(\u000D)

\xnn 由十六进制数 nn 指定的拉丁字符

\uxxxx 由十六进制数 xxxx 指定的 unicode 字符

\cX 控制字符 ^x

正则表达式中,许多标点符号也具有特殊含义,它们是:

^ $ . * + ? = ! : | \ / ( ) { }

将直接量字符单独放进方括号内组成了字符类(charactor class)

表10-2

字符 匹配

[…] 方括号内的任意字符

[^…] 不在方括号内的任意字符

. 除换行符和其它 Unicode 行终止符之外的任意字符

\w 任何 ASCII 字符组成的单词,等价于 [a-zA-Z0-9]

\W 任何不是 ASCII 字符组成的单词,等价于 [^a-zA-Z0-9]

\s 任何 Unicode 空白符

\S 任何非 Unicode 空白符

\d 任何 ASCII 数字,等价于 [0-9]

\D 任何非 ASCII 数字,等价于 [^0-9]

[\b] 退格直接量

表10-3

字符 含义

{n, m} 匹配前一项至少 n 次,但不能超过 m 次

{n,} 匹配前一项 n 次或者更多次

{n} 匹配前一项 n 次

? 匹配前一项 0 次或者 1 次,也就是说前一项是可选的,等价于 {0,1}

+ 匹配前一项 1 次或者多次,等价于 {1,}

* 匹配前一项 0 次或者多次,等价于{0,}

举例说明:

/\d{2,4}/           // 匹配 2 ~ 4 个数字
/\w{3}\d?/          // 匹配三个单词和一个可选的数字
/\s+java\s+/        // 匹配前后带有一个或者多个空白字符串 "java"
/[^(]*/             // 匹配一个或多个非左括号字符

非贪婪的重复

表10-3 中列出一匹配重复字符是尽可能多地匹配,而且允许后续的正则表达式继续匹配。因此,我们称之为「贪婪的」匹配。我们同样可以使用正则表达式进行非贪婪匹配。只需在特匹配的字符后跟随一个问题即可:「??」、「+?」、「*?」或「{1,5}?」

选择、分级和引用

表10-4

字符 含义

| 选择,匹配的是该符号左边的子表达式或者右边的子表达式

(…) 组合,将几个项组合为一个单元,这个单元可通过「*」、「+」、「?」和「|」等符号
加以修饰,而且可以记住和这个组合相匹配的字符串
以供此后的引用使用

(?:…) 只组合,把项组合到一个单元,但不记忆与该组想匹配的字符

\n 和第 n 个分级第一次匹配的字符相匹配,组是圆括号中的子表达式
(也有可能是嵌套的),组索引是从左到右的左括号数,
「(?:」形式的分组不编码

指定匹配位置

表10-5

字符 含义

^ 匹配字符串的开头

$ 匹配字符串的结尾

\b 匹配一个单词的边界

\B 匹配非单词边界的位置

(?=p) 零宽正向先行断言,要求接下来的字符都与 p 匹配,但不能包括匹配 p 的那些字符

(?!p) 零宽负向先行断言,要求接下来的字符都不与 p 匹配

/reg/flag

标识是放在斜扛右边的,通常有 i, g, m 三种

  • i 执行不区分大小写的匹配
  • g 执行一个全局匹配,即 找到所有的匹配,而不是找到第一个就停止
  • m 多行匹配模式

用于模式匹配的 string 方法

String 支持 4 种使用正则表达式的方法

String.prototype.search()

search() 方法返回第一个与之匹配的子串起始位置,如果找不到匹配的子串,它将返回 -1

"JavaScript".search(/script/i);         // => 4

如果 search() 参数不是正则表达式,则首先会 通过 RegExp 构造函数将它转换成正则表达式,search() 方法不支持全局检索,因为它 忽略 正则表达式参数中的标识 g

String.prototype.replace()

str.replace(regexp|substr, newSubStr|function)

replace() 方法用以执行检索与替换操作,正则表达式如果带标识 g,则会替换所有匹配子串

// 将所有不区分大小写的 javascript 都替换成 JavaScript
text.replace(/javascript/gi);

// 用中文引号替换英文应该引号,同时要保持引号之间的内容(存储在 $1 中)没有被修改
var quote = /"([^"]*)"/g;
text.replace(quote, '“$1”')

String.prototype.match()

match() 方法返回一个由匹配结果组成的数组,如果没有标识全局搜索,match() 只检索第一个匹配

"1 plus 2 equals 3".match(/\d+/g);  // => ["1", "2", "3"]

RegExp 对象

RegExp(pattern [, flags])

RegExp 构造函数一般用在动态创建正则表达式的时候,这种情况往往没办法通过写死在代码中的正则直接量来实现,比如检索字符串是用户输出的

RegExp 的属性

每个 RegExp 对象都包含 5 个属性:

  • source 只读字符串,包含正则表达式的文本
  • global 只读布尔值,说明正则表达式是否带全局标识 g
  • ignoreCase 也是一个只读布尔值,说明正则表达式是否带标识 i
  • multiline 也是一个只读布尔值,说明正则表达式是否带标识 m
  • lastIndex 它是一个可读/写的整数。如果匹配模式带有 g 标识,这个属性存储在整个字符串中下一次检索的开始位置

RegExp 的方法

exec()

exec() 对一个指定的字符串执行一个正则表达式,如果没有找到任何匹配,它就返回 null,但如果它找到一个匹配,将返回一个数组

var pattern = /Java/g;
var text = "JavaScript is more fun than Java!";
var result;
while((result = pattern.exec(text)) != null) {
    console.log("Matched '%s' at position '%s'; next search begins at %s",
        result[0],
        result.index,
        pattern.lastIndex);
}
// Matched 'Java' at position '0'; next search begins at 4
// Matched 'Java' at position '28'; next search begins at 32

test()

test() 对方法转入字符串进行检测,匹配到结果返回 true,否则返回 false

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK