JS中的正则表达式-02

89 阅读2分钟

正则表达式的flag标识

正则表达式具有可选的flag,这些flag可以单独使用,也可以任意组合使用,不分顺序。flag可选值见下表:

flag描述对应属性名
d生成hasIndices
g全局搜索global
i大小写不敏感(不区分大小写)ignoreCase
m允许^$匹配新行(多行搜索)multiline
s允许.匹配新行字符串(匹配换行符)dotAll
uUnicode 将一个匹配视为 Unicode 序列(Unicode 码)unicode
y搜索类型变为sticky,从目标字符串的当前位置开始匹配sticky

字符串的match(regexp)方法

match(regexp)语法

regexp 正则表达式

return 一个数组 Array

  • regexp 存在 g 标识时,会返回所有匹配到的字符串;
  • regexp 不存在 g 标识时,会返回带有index, input, groups属性的数组,与正则表达式的exec方法返回值一致。

示例 match

该示例中,正则表达式存在 g标识,会返回所有匹配到的字符串;

let str01 = 'The simplest approach will prove to be the most effective', 
str03 = '最简单的方法往往是最有效的'

/** g 全局搜索 */
let reg01 = /The/g

/** i 不区分大小写 */
let reg02 = new RegExp('the', 'ig')
let reg03 = /的/g

let arr01 = str01.match(reg01)
let arr02 = str01.match(reg02)
let arr03 = str03.match(reg03)

console.log(arr01);  // [ 'The' ]
console.log(arr02);  // [ 'The', 'the' ]
console.log(arr03);  // [ '的', '的' ]

character classes 字符类

字符类用于区分不同类型的字符

字符含义
[xyz]
[a-c]
匹配 [ 中括号里面的任意一个字符 ],可以使用 - 来指定字符的范围。例如 [a-c] 匹配 a、b、c 任意一字符。
[^xyz] [^a-c]匹配任意一个不包含在 [] 里面的字符
.任意一个除了行终止符以外的字符,行终止符主要有:\n, \r
\d任意一个阿拉伯数字,即 [0-9]
\D任意一个非数字字符,即 0-9
\w字母数字下划线,即 [a-zA-Z0-9_]
\W非字母数字下划线,即 a-za-z0-9_
\s空白字符,包括空格,Tab,制表符,行终止符
\S非空白符
\ttab 键水平制表符(水平缩进)
\r回车符
\n换行符
\v垂直制表符
\f制页符
[\b]退格符(backspace)(注意 \b 是单词边界)
\0NULL
\cX当 X 为 [A-Z] 时,匹配脱字符 caret notation
\xhh使用两个 16 进制数值(hh)匹配字符
\uhhhh使用 4 个 16 进制数值(hhhh)匹配 UTF-16 字符
\u{hhhh}\u{hhhhh}当使用 flags 属性为 u 时,使用 16 进制数值匹配字符
\p{UnicodeProperty}, \P{UnicodeProperty}基于 UnicodeProperty 匹配字符,比如中文、日文、表情等(配合 flag:u 使用)
\转义符,意味着后面的一位字符特殊对待。通产而言有两种情况: 1. 将普通字面量转为特殊字符:\d 不再匹配 d,而是匹配数字; 2. 将特殊字符转为普通字面量:\. 不再匹配任意一个除了行终止符以外的字符,而是匹配 .
x|yx或者y;
[xy] 相比,使用或运算 | 可以匹配多个字符连接而成的单词,比如 red|green (注意这里运算符|前后不需要空格,如果有空格,空格也会参与匹配)表示匹配red或green

示例 字符类

该示例中,正则表达式存在 g标识,会返回所有匹配到的字符串;

const str40 = 'username: 天涯路儿, uid: 279656749, from: bilibili, fans: 67'

/** 匹配单词开头 a-f 中的任一字符 */
const reg40 = /\b[a-f]/g
/** 匹配两个连在一起的数字 */
const reg41 = /\d\d/g
/** 匹配非空白符, (注意这里有个,) */
const reg42 = /\S,/g
/** 匹配数字字母下划线, (注意这里有个,) */
const reg43 = /\w,/g
/** 匹配中文 */
const reg44 = /[\u4e00-\u9fa5]/g
/** 匹配中文 */
const reg45 = /\p{Script=Han}/gu
/** 匹配数字 */
const reg46 = /\p{N}/gu

let res40 = str40.match(reg40)
let res41 = str40.match(reg41)
let res42 = str40.match(reg42)
let res43 = str40.match(reg43)
let res44 = str40.match(reg44)
let res45 = str40.match(reg45)
let res46 = str40.match(reg46)


console.log(res40); // [ 'f', 'b', 'f' ]
console.log(res41); // [ '27', '96', '56', '74', '67' ]
console.log(res42); // [ '儿,', '9,', 'i,' ]
console.log(res43); // [ '9,', 'i,' ]
console.log(res44); // [ '天', '涯', '路', '儿' ]
console.log(res45); // [ '天', '涯', '路', '儿' ] 
console.log(res46); // [  '2', '7', '9', '6',  '5', '6', '7', '4',  '9', '6', '7']

Groups and backreferences捕获组和组引用

Groups将多个匹配组织为一个整体,当使用一个正则表达式去匹配一个字符串时,捕获组将提供额外的信息。

字符含义
(x)匹配x并记住(捕获组)
一个正则表达式中可以有多个捕获组,捕获组的顺序与左括号(的位置顺序对应;可以从匹配结果中,通过下标访问捕获元素([0], ..., [n])或正则表达式的属性($1, ..., $n)来访问
(?<name>x)命名捕获组:尖括号<>里面写捕获组的名字 name, 将会匹配x并将x保存到groups属性中
(?:x)不捕获组:匹配但不记住
被匹配的字符串无法通过下标index ([0], ..., [n])或正则表达式的属性($1, ..., $n)访问
\nn为正整数时,引用正则表达式的第n个捕获组(即第n个小括号()里的内容)
\k<name>通过名字name引用上一个命名捕获组

示例 使用捕获组

该例子使用()捕获组,从匹配结果中,通过下标访问捕获元素,正则表达式没有使用g标识(flag),字符串的 match 方法与正则表达式的 exec 方法的返回值一致

const str50 = `芭芭拉:节奏: S, 音准: S, 技巧: S, 感情: S, 气息: S; `

/** (\w) 捕获\w (字母数字下划线) 匹配项 */
const reg50 = /节奏: (\w), 音准: (\w), 技巧: (\w), 感情: (\w), 气息: (\w)/
const reg51 = /节奏: (\w), 音准: (\w), 技巧: (\w), 感情: (\w), 气息: (\w)/

/** 如果没有 g 标识(flag), 字符串的 match 方法与正则表达式的 exec 方法的返回值一致, 会返回带有index, input, groups属性的数组 */
let arr50 = str50.match(reg50)
let res50 = ''
console.log(arr50);
/** [
  '节奏: S, 音准: S, 技巧: S, 感情: S, 气息: S',
  'S',
  'S',
  'S',
  'S',
  'S',
  index: 4,
  input: '芭芭拉:节奏: S, 音准: S, 技巧: S, 感情: S, 气息: S; ',
  groups: undefined
] */
let arr51 = reg51.exec(str50)
let res51 = ''
console.log(arr51);
/** [
  '节奏: S, 音准: S, 技巧: S, 感情: S, 气息: S',
  'S',
  'S',
  'S',
  'S',
  'S',
  index: 4,
  input: '芭芭拉:节奏: S, 音准: S, 技巧: S, 感情: S, 气息: S; ',
  groups: undefined
] */

/** 通过下标 index 访问匹配结果元素, 捕获组顺序从 1 开始 */
for (let i = 0; i < 5; i++) {
  res50 += arr50[i + 1] + '\t'
  res51 += arr51[i + 1] + '\t'
}

console.log('节奏\t 音准\t 技巧\t 感情\t 气息\t'); // 节奏     音准    技巧    感情    气息
console.log(res50); // S       S       S       S       S
console.log(res51); // S       S       S       S       S

示例 命名捕获组

该示例中,使用了命名捕获组,捕获的字符串会保存到groups属性中

const str50 = `芭芭拉:节奏: S, 音准: S, 技巧: S, 感情: S, 气息: S; `

/** 命名捕获组, 通过 \k<level> 来引用 (?<level>\w) 中的捕获项, 即只有所有等级全为 S 时,才会匹配 */
const reg52 = /节奏: (?<level>S), 音准: (\k<level>), 技巧: (\k<level>), 感情: (\k<level>), 气息: (\k<level>)/
/** 命名捕获组 */
const reg53 = /节奏: (?<rhythm>\w), 音准: (?<intonation>\w), 技巧: (?<skill>\w), 感情: (?<emotion>\w), 气息: (?<breath>\w)/

let res52 = reg52.test(str50)

/** 命名捕获组:会将匹配项保存到 groups 属性中 */
let arr53 = str50.match(reg53)
console.log(arr53.groups);
/** [Object: null prototype] { rhythm: 'S', intonation: 'S', skill: 'S', emotion: 'S', breath: 'S'} */
let obj = arr53.groups
let res53 = ''
for (const key in obj) {
  res53 += obj[key] + '\t'
}

console.log('节奏\t 音准\t 技巧\t 感情\t 气息\t'); // 节奏     音准    技巧    感情    气息
console.log(res52); // true
console.log(res53); // S       S       S       S       S