Javascript对象 - 正则表达式入门

1,475 阅读4分钟

在学习之前我们先提出一些问题(带着问题去看):

  • 定义正则表达式的方式有哪几种?
  • 测试正则表达式的方法都有哪些?
  • 为什么使用正则表达式?
  • 什么是修饰符,g,i,m 都代表什么意思 ?
  • []代表什么?
  • 方括号中的^ 和非方括号的^ 含义一样吗?
  • 什么是贪婪模式,什么是非贪婪模式?
  • ()是什么意思,子表达式的值会被存储吗?怎么获取到某个表达式?
  • ?:、?=、 ?! 都分别代表了什么?
  • *、+、? 都代表什么?

你能答上吗?

为什么使用正则表达式?

典型的搜索和替换功能 要求您提供 确切的文本。静态文本足够,但是若搜索动态文本,很困难。使用正则表达式可以:

  • 验证输入的字符串是否符合要求
  • 删除替换特定的文本
  • 提取子字符串

在现实中比如,验证邮箱输入是否符合格式,隐藏电话号码中间四位,替换某些html格式标记。

1.【定义】正则表达式的方式有2种:

1.1 字面量方式: var reg = /\d/; 斜杠包围

1.1.1 字符串的2种最常用的匹配方法:

  • str.match(regexp): (参数是正则表达式)=> 返回结果数组 || null
  • str.replace(regexp|substr, newSubStr|function):返回新字符串(原字符串不会改变)

1.2 构造函数方式: new RegExp('\\d'); 引号包围

1.2.1 RegExp(标准内置对象):对象用于将文本与一个模式匹配。

1.2.1.1 RegExp的属性:

1.2.1.2 RegExp对象的最常用的2种匹配方法:

  • regexp.exec(str):(参数是字符串) => 返回结果数组 || null
  • regexp.test(str):(参数是字符串) => 返回boolean

📢:RegExp 里的\d 表示匹配[0-9]的数字,但是在参数字符串内需要使用反斜杠转义,序列 "\\" 匹配 "\"!!!

🌰eg:

const  reg = /\d/;
const  string = '123';
const  reg1 = new RegExp('\\d');
// 方式一:字符串的方法
string.match(reg); // ['1', index: 0, input: '123', groups: undefined]

// 方式二:字符串的方法
string.replace(reg,'-'); // 返回新字符串'-23',原字符串不变

// 方式三:对象方法
reg1.exec(string); // ['1', index: 0, input: '123', groups: undefined]

// 方式四:对象方法
reg1.test(string); // true

2. 语法:

正则表达式是由【普通字符】以及【特殊符号】组成的文字模式。

修饰符(也叫标记):

标记:用于指定【额外的】匹配策略, 【位于表达式之外

下表列出了正则表达式常用的修饰符:

修饰符含义描述
iignore - 不区分大小写不区分大小写: A 和 a 没有区别。
gglobal - 全局匹配查找所有的匹配项。
mmulti line - 多行匹配使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。
s特殊字符圆点 . 中包含换行符 \n默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。

📢:

  • 如果没有修饰符g的情况下,只会匹配第一个找到的字符,加上g后可以匹配多个字符。
  • 同理,没加m只能匹配第一行,加上m后可以多行匹配
    • 【只有当使用^和$模式时才会起作用,在其他的模式中,加不加入m都可以进行多行匹配】
  • 所以如果mg一起就可以实现【多行全局】匹配
// ^$ 模式: 
var str = "hello
2world
3global"

var pattern = /^\d/;
var pattern1 = /^\d/g;
var pattern2 = /^\d/m;
var pattern3 = /^\d/gm;
str.match(pattern); // 没有匹配 => 第一行没有,没找到
str.match(pattern1); // 没有匹配 => 第一行没有,没找到
str.match(pattern2); // 2=> 只有m 返回第一个找到的,第一行找不到,去第二行找
str.match(pattern3); // 2, 3 => mg一起可以实现多行全局匹配

// 非^$ 模式:加不加m都一样

var pattern4 = /\d/;
var pattern5 = /\d/m;
str.match(pattern4); // 2
str.match(pattern5); // 2

元字符(特殊字符):

📢:如要匹配特殊字符本身,需要在前加转义字符\ 进行转义。!!!!
例如, 序列 '\\' 匹配 "\",而 '\(' 则匹配 "("

正则中的特殊字符11个:

特殊字符描述
$要匹配 $ 字符本身,请使用 \$
( )要匹配这些字符,请使用 \( 和 \)
*要匹配 * 字符,请使用 \*。
+要匹配 + 字符,请使用 \+。
.要匹配 . ,请使用 \. 。
[标记一个中括号表达式的开始.要匹配 [,请使用 \[。
?要匹配 ? 字符,请使用 \?。
\将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
^要匹配 ^ 字符本身,请使用 \^。
{标记【限定符】表达式的开始。要匹配 {,请使用 \{。
|要匹配 |,请使用 \|

那么特殊字符除了自身的含义外,还有以下其他的意义。

再说一次:所有正则表达式都是由普通字符(例如字符 a - z) 和元字符 组成的。

1. 限定符: * + ? {n,m}

限定符用来指定正则表达式的一个【给定组件】必须要【出现多少次】才能【满足匹配】。有共6种:

  1. * :等于{0,}
  2. + :等于{1,}
  3. ? :等于{0,1}, 放在其他限定符后表示最小匹配
  4. {n} 
  5. {n,} 
  6. {n,m} 

贪婪模式(默认):* , +

尽可量多的匹配,如* , +

非贪婪模式(最小匹配):?

尽可量少的匹配,如?,最小匹配并不是只匹配一个

在任何一个【限制符】 (*, +, ?, {n}, {n,}, {n,m})之后放置 ?,该表达式从"贪婪"表达式转换为"非贪婪"表达式(最小匹配)。

eg🌰:

var str = "goood go";
var reg = /o+?/;
str.match(reg); // 'o'

var reg1 = /o+/;
str.match(reg1); // 'ooo'

var reg2 = /go(o)?/g;
str.match(reg2); // ['goo', 'go']

解释一下:+ 的意思是匹配一个或者多个{1,}。
所以'o+?' 将匹配单个 "o",+?就是最小匹配,也就是匹配1个
而 'o+' 将匹配所有 'o'。
? 单独使用时,表示0个或者1个,所以go 和goo都可以被匹配到

eg2🌰: "dxxxdxxxd" 举例:

表达式匹配结果
[(d)(/w+?)]"/w+?" 将尽可能少的匹配第一个 "d" 之后的字符,结果是:"/w+?" 只匹配了一个 "x"
[(d)(/w+?)(d)]为了让整个表达式匹配成功,"/w+?" 不得不匹配 "xxx" 才可以让后边的 "d" 匹配,从而使整个表达式匹配成功。因此,结果是:"/w+?" 匹配 "xxx"

2. 定位符:^$\b\B

  • 描述字符串或单词的边界
    • ^ 和 $ 分别指字符串的开始与结束
    • \b 描述单词的前或后边界
    • \B 表示非单词边界。
      • 单词边界:单词和空格之间的位置
      • 非单词边界:任何其他位置

正则表达式的定位符有:

字符描述
^匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。
$匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
\b匹配一个单词边界,即字与空格间的位置。
\B非单词边界匹配。

🌰eg:

const str = 'hello, what is your name?';
str.match(/\bw/); // 'w'
str.match(/\be/); // null

3. 选择项 - 捕获分组

  • ():包含选择项,表示捕获分组
    • 会保存每个分组里匹配到的值
    • 可以通过\2来查看第2个分组(缓存区)捕获到的值
    • 副作用: 使相关的匹配会被缓存,存储到一个临时缓冲区中
      • 此时可用 ?: 放在第一个选项前来消除这种副作用
  • | : 分隔相邻选择项

3.1 反向引用 \n (n是具体的数字)

反向引用的最简单的、最有用的应用之一:是提供查找文本中两个相同的相邻单词的匹配项的能力

🌰eg:查找重复的单词

var str = "Is is the cost of of gasoline going up up"; 
var patt1 = /\b([a-z]+) \1\b/igm;  // 
str.match(patt1); // Is is,of of,up up

解释一下正则表达式:
():表示捕获分组
[a-z]+ :表示包括1个或多个字母,
\1 :指定第一个子匹配项。是对第一个捕获到的分组的引用,也就是[a-z]+
前后是【单词边界元字符\b】:确保只检测整个单词
igm修饰符:代表【多行不缺分大小写全局匹配】

3.2 非捕获元:

可以使用非捕获元字符 ?:、?= 或 ?! 来重写捕获,忽略对相关匹配的保存。

  1. ?:
  2. ?= :另一层意义是正向肯定预查
  3. ?! :另一层意义是正向否定预查

4. 断言:

正则表达式引擎在匹配字符串和表达式时,是从前向后逐个扫描字符串中的字符。

  1. (?=pattern) 零宽正向先行断言
  2. (?!pattern) 零宽负向先行断言
  3. (?<=pattern) 零宽正向后行断言
  4. (?<!pattern) 零宽负向后行断言(zero-width negative lookbehind assertion)

它们只匹配某些位置,在匹配过程中,不占用字符,所以被称为 "零宽"

📢: Javascript 不支持后行断言,ES2018 引入[后行断言],V8 引擎 4.9 版(Chrome 62)已经支持。

eg🌰:

// 能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。
const reg1 = /Windows(?=95|98|NT|2000)/;
// 能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。
const reg2 = /Windows(?!95|98|NT|2000)/;
// 能匹配2000windows,不能匹配3.1window
const reg3 = /(?<=95|98|NT|2000)Windows/;
// 能匹配3.1windows 不能匹配2000windows
const reg4 = /(?<!95|98|NT|2000)Windows/;


"a regular expression".match(/re(?=gular)./); // 'reg'
"a regular expression".match(/re(?=gular)/); // 'regular'

解释一下: ?=、 ?!是在字符串的后面,前者是有,后者是排除。 ?<=和?<! 是字符串的前面。

普通字符:

所有大写和小写字母、所有数字、所有标点符号和一些其他符号(可打印,不可打印都包含)

  • [ABC]: 匹配方括号内的所有字符
  • [^ABC]:匹配除了方括号内的所有字符
  • [A-Z]:匹配A-Z 之间的所有字符,
    • [a-z]代表匹配a-z之间所有的小写字母
  • . :除换行符(\n、\r)之外的任何单个字符,相等于 [^\n\r]。
  • [\s\S]: 匹配所有。
    • \s 是匹配所有空白符,包括换行,
    • \S 非空白符,不包括换行。
  • \w: 匹配字母、数字、下划线。等价于 [A-Za-z0-9_]

eg🌰:

const result = "hello world".match(/\s\S/);  // ' w'
const result = "hello world".match(/[\s\S]/);  // 'h'
 
 

非打印字符:

字符描述
\cx匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\f匹配一个换页符。等价于 \x0c 和 \cL。
\n匹配一个换行符。等价于 \x0a 和 \cJ。
\r匹配一个回车符。等价于 \x0d 和 \cM。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t匹配一个制表符。等价于 \x09 和 \cI。
\v匹配一个垂直制表符。等价于 \x0b 和 \cK。

部分元字符使用场景:

字符描述
^【定位符】- 匹配输入字符串的开始位置。在[^abc]方括号中使用时,表示匹配除了abc外的字符
$【定位符】- 匹配输入字符串的结尾位置。如设置了RegExp对象的修饰符m,则$也匹配'\n'或'\r'
{n}【限定符】- 表达式重复n次,比如:"/w{2}" 相当于 "/w/w";"a{5}" 相当于 "aaaaa"
{n,m}【限定符】- 最少匹配 n 次且最多匹配 m 次
*【限定符】- 匹配前面的子表达式0次或多次。等于{0,}
+【限定符】- 匹配前面的子表达式1次或多次。等于{1,}
?【限定符】- 匹配前面的子表达式0或1次,等于{0,1}。或指明一个非贪婪限定符
( )【选择】-标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用
.匹配除换行符 \n 之外的任何单字符
x|y【选择】-指明两项之间的一个选择。
[abc]字符集合。匹配abc中的任意一个字符
[^abc]负字符集合。匹配除了abc中的任意一个字符
[a-z]字符范围。匹配a-z中的任意一个字符
\d匹配一个数字字符。等价于 [0-9]。
\D匹配一个非数字字符。等价于 [^0-9]。
\w匹配字母、数字、下划线。等价于'[A-Za-z0-9_]'。
\W匹配非字母、数字、下划线。等价于 '[^A-Za-z0-9_]'。

注意事项 :

  • [abc]、\d、\w、.等: 可以匹配【多种字符中的】任意一个,记住,只能匹配到一个

    • 加上限制符* + {n,m} 等可以进行重复匹配,不需要重写书写表达式
      • {n,m}: m 和 n 均为非负整数,请注意在逗号和两个数之间不能有空格。
  • 不能将限定符与定位符一起使用:不允许诸如 ^* 之类的表达式

  • 在方括号中使用^时,如[^abc]:不再表示字符串开始位置,表示匹配除了abc外的字符

  • 如要匹配特殊字符本身,需要在前加转义字符\ 进行转义

  • (.|\n): 匹配包括 '\n' 在内的任何字符。

运算符优先级:

  • 正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。
  • 相同优先级的从左到右进行运算,不同优先级的运算先高后低。

下面字符优先级从高->低

  1. \
  2. (), (?:), (?=), []
  3. 限定符 *, +, ?, {n}, {n,}, {n,m}
  4. ^, $, \任何元字符、任何字符
  5. |

答案:

  • 定义正则表达式的方式有哪几种?
    • 2种,var reg=/\d/ ,和new RegExp对象
  • 测试正则表达式的方法都有哪些?
    • test
    • match
    • replace
    • exec
  • 为什么使用正则表达式?
    • 搜索,替换删除指定文本,数据验证等,灵活强大
  • 什么是修饰符,g,i,m 都代表什么意思 ?
    • 在表达式之外,g全局匹配,i不区分大小写,m多行匹配
  • []中括号表达式代表什么?
    • [abc]匹配中括号内的任意一个字符,只匹配一个
  • 方括号中的^ 和非方括号的^ 含义一样吗?
    • /[^abc]/: 匹配除了abc的任意一个字符。
    • /^abc/: 匹配以abc开头的字符串。
  • 什么是贪婪模式,什么是非贪婪模式?
    • 任意限制符后加?代表非贪婪匹配(最小匹配),默认是贪婪匹配。
  • ()是什么意思,子表达式的值会被存储吗?怎么获取到某个表达式?
    • ()捕获分组,会被存储在缓存区,可使用\1...获取到,replace中使用$0...
  • ?:、?=、 ?! 都分别代表了什么?
    • 非捕获元,?:可以消除副作用,不缓存分组的值。 ?=,?!还有先行断言的意义
  • *、+、? 都代表什么?
    • 限制符 * : {0,} 0个、1个 、多个
    • 限制符 + : {1,} 至少一个或多个
    • 限制符 ? : {0,1} 最多一个