专栏首页前端自习课【JS】128-重温基础:正则表达式

【JS】128-重温基础:正则表达式

「本章节复习的是JS中的正则表达式,JS中用来匹配字符串的强大工具。」

前置知识: JS中的正则表达式是用来匹配字符串中指定字符组合的模式。 另外需要记住:正则表达式也是对象。

1.创建正则表达式

  • 使用一个正则表达式字面量:
let reg = /ab+c/;
let reg = /^[a-zA-z]/gi;
  • 使用RegExp对象: new RegExp(str[, attr])接收2个参数,str是一个字符串,指定正则表达式匹配规则,attr可选,表示匹配模式,值有g(全局匹配),i(区分大小写的匹配)和m(多行匹配)。
let reg = new RegExp('ab+c');
let reg = new RegExp(/^[a-zA-z]/, "gi");
let reg = new RegExp("^[a-zA-z]", "gi");

正则表达式的返回值,是一个新的RegExp对象,具有指定的模式和标志。 「返回信息介绍」

对象

属性

描述

案例中对应的值

reg

lastIndex

下一个匹配的索引(仅在使用g参数时可用)

0

reg

source

模式文本。在正则表达式创建时更新,不执行。

"ab+c"

reg

ignoreCase

是否使用了 "i" 标记使正则匹配忽略大小写。

true

reg

global

是否使用了 "g" 标记来进行全局的匹配。

true

reg

multiline

是否使用了 "m" 标记使正则工作在多行模式。

false

「关于正则表达式的一些方法属性,文章后面介绍,这里先复习定义和使用」

2.使用正则表达式

JS的正则表达式可以被用于:

  • RegExp对象的exectest方法;
  • String对象的matchreplacesearchsplit方法。

2.1 RegExp对象方法

检索字符串中指定的值。返回找到的值,并确定其位置。

2.1.1 exec(str)

str: 需要检索的字符串。 若检索成功,返回匹配的数组,否则返回null。

let str = "hello leo!";
let reg = new RegExp("leo", "g");
let result = reg.exec(str);
// 也可以写成
let result = /leo/g.exec("hello leo!");

/*
[
    0: "leo",
    groups: undefined,
    index: 6,
    input: "hello leo!",
    length: 1
]
*/

let result2 = /(leo \S)/g.exec("hello leo hi leo!");
/*
    0: "leo hi"
    1: "leo hi"
    2: "hi"
    groups: undefined
    index: 6
    input: "hello leo hi leo!"
    length: 3
*/

「返回信息介绍」

对象

属性

描述

案例中对应的值

result

[0]

匹配到的所有字符串

"leo"

result

input

初始字符串。

"hello leo!"

result

index

在输入的字符串中匹配到的以0开始的索引值。

6

result2

[1],...,[n]

括号中的分组捕获

[1]=> "leo hi";[2] => "hi"

2.1.2 test(str)

str:需要检索的字符串。 若匹配成功返回true否则false。 等价于 reg.exec(str) != null

let str = "hello leo!";
let res = /^leo/.test(str);   // fasle

^str表示匹配以str开头的字符串,这些符号文章后面会介绍。

「注意:」

若正则使用全局标志( g ),则test()会改变正则表达式的 lastIndex 属性,连续调用test()方法,后续的执行将会从 lastIndex 处开始匹配字符串,(exec() 同样改变正则本身的 lastIndex属性值):

var regex = /leo/g;

// regex.lastIndex is at 0
regex.test('leo'); // true

// regex.lastIndex is now at 3
regex.test('leo'); // false

2.2 String对象方法

检索与正则表达式相匹配的值。

str.search(reg)str:被检索的源字符串。 reg:可以是需要检索的「字符串」,也可以是需要检索的RegExp对象,可以添加标志,如i

若检索成功,返回「第一个」RegExp对象匹配的字符串的起始位置,否则返回-1

let str = "hello leo!";
let res = str.search(/leo/g);  // 6

let str1 = "hello leoleoleoleo!";
let res1 = str.search(/leo/g); // 6
let res2 = str.search(/pingan/g); // -1

2.2.2 match

str.match(reg)str:被检索的源字符串。 reg:可以是需要检索的「字符串」,也可以是需要检索的RegExp对象,可以添加标志,如i

若检索成功,返回与reg匹配的所有结果的一个「数组」,数组的第一项是进行匹配完整的字符串,之后的项是用圆括号捕获的结果,否则返回null

let str = 'For more information, see Chapter 3.4.5.1';
let reg = /see (chapter \d+(\.\d)*)/i;
let result = str.match(reg);
/*
logs [ 'see Chapter 3.4.5.1',
       'Chapter 3.4.5.1',
       '.1',
       index: 22,
       input: 'For more information, see Chapter 3.4.5.1' ]
*/

'see Chapter 3.4.5.1' 是整个匹配。 'Chapter 3.4.5.1''(chapter \d+(\.\d)*)'捕获。 '.1' 是被'(\.\d)'捕获的最后一个值。 'index' 属性(22)是整个匹配从零开始的索引。 'input' 属性是被解析的原始字符串。

2.2.3 replace

将字符串中「指定字符」替换成「其他字符」,或替换成一个与正则表达式匹配的字符串。 str.replace(sub/reg,val):

  • str: 源字符串
  • sub: 使用字符串来检索被替换的文本
  • reg: 使用RegExp对象来检索来检索被替换的文本
  • val: 指定替换文本 返回替换成功之后的字符串,不改变源字符串内容。
let str = "hello leo!";
let res = str.replace('leo','pingan');//"hello pingan!"

「val可以使用特殊变量名」

插入一个 "$"。
let str = "hello leo!";
let res = str.replace(/(\w+)\s* \s*(\w+)/, "$2:$1");
// "leo:hello!"

2.2.4 split

将一个字符串,按照指定符号分割成一个字符串数组。 str.split(sub[, maxlength]):

  • str: 源字符串
  • sub: 指定的分割符号或正则
  • maxlength: 源字符串
let str = "hello leo!";
let res = str.split();   //["hello leo!"]
let res = str.split(""); //["h", "e", "l", "l", "o", " ", "l", "e", "o", "!"]
let res = str.split(" ");//["hello", "leo!"]
let res = str.split(/\s+/);//["hello", "leo!"]

let res = str.split("",3);//["h", "e", "l"]

2.3 使用情况

  • 当我们想要查找一个字符串中的一个匹配「是否找到」,可以用testsearch方法。
  • 当我们想要得到匹配的「更多信息」,我们就需要用到execmatch方法。

3.正则表达式符号介绍

详细的每个符号的用法,可以查阅 W3school JavaScript RegExp 对象

3.1 修饰符

执行对大小写不敏感的匹配。
let str = "hello leo!"
let res = /Leo/i.test(str); // i 不区分大小写 所以返回true
let res = /Leo/.test(str);  // fasle

3.2 方括号

用于查找指定返回之内的字符:

查找方括号之间的任何字符。
let str = "hello leo!";
let res = str.match(/[a-m]/g);
//["h", "e", "l", "l", "l", "e"]
let res = str.match(/[^a-m]/g);
//["o", " ", "o", "!"]

3.3 元字符

元字符是拥有特殊含义的字符:

查找单个字符,除了换行和行结束符。
let str = "hello leo hi pingan!";
let res = str.match(/o\s/g);
//["o ", "o "]
let res = str.match(/\s/g);
//[" ", " ", " "]

3.4 量词

匹配任何包含至少一个 n 的字符串。
let str = "hello leo!";
let res = str.match(/^hello/g);
// ["hello"]
let res = str.match(/^pingan/g);
//null

4. 正则表达式拓展(ES6)

4.1 介绍

在ES5中有两种情况。

  • 参数是「字符串」,则第二个参数为正则表达式的修饰符。
let a = new RegExp('abc', 'i');
// 等价于
let a = /abx/i;
  • 参数是「正则表达式」,返回一个原表达式的拷贝,且不能有第二个参数,否则报错。
let a = new RegExp(/abc/i);
//等价于
let a = /abx/i;

let a = new RegExp(/abc/, 'i');
//  Uncaught TypeError

ES6中使用: 第一个参数是正则对象,第二个是指定修饰符,如果第一个参数已经有修饰符,则会被第二个参数覆盖。

new RegExp(/abc/ig, 'i');

4.2 字符串的正则方法

常用的四种方法:match()replace()search()split()

4.3 u修饰符

添加u修饰符,是为了处理大于uFFFF的Unicode字符,即正确处理四个字节的UTF-16编码。

/^\uD83D/u.test('\uD83D\uDC2A'); // false
/^\uD83D/.test('\uD83D\uDC2A');  // true

由于ES5之前不支持四个字节UTF-16编码,会识别为两个字符,导致第二行输出true,加入u修饰符后ES6就会识别为一个字符,所以输出false

「注意:」 加上u修饰符后,会改变下面正则表达式的行为:

  • (1)点字符 点字符(.)在正则中表示除了「换行符」以外的任意单个字符。对于码点大于0xFFFF的Unicode字符,点字符不能识别,必须加上u修饰符。
var a = "?";
/^.$/.test(a);  // false
/^.$/u.test(a); // true
  • (2)Unicode字符表示法 使用ES6新增的大括号表示Unicode字符时,必须在表达式添加u修饰符,才能识别大括号。
/\u{61}/.test('a');      // false
/\u{61}/u.test('a');     // true
/\u{20BB7}/u.test('?'); // true
  • (3)量词 使用u修饰符后,所有量词都会正确识别码点大于0xFFFF的 Unicode 字符。
/a{2}/.test('aa');    // true
/a{2}/u.test('aa');   // true
/?{2}/.test('??');  // false
/?{2}/u.test('??'); // true
  • (4)i修饰符 不加u修饰符,就无法识别非规范的K字符。
/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true

「检查是否设置u修饰符:」使用unicode属性。

const a = /hello/;
const b = /hello/u;

a.unicode // false
b.unicode // true

4.4 y修饰符

y修饰符与g修饰符类似,也是全局匹配,后一次匹配都是从上一次匹配成功的下一个位置开始。区别在于,g修饰符「只要」剩余位置中存在匹配即可,而y修饰符是必须从「剩余第一个」开始。

var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;

r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]

r1.exec(s) // ["aa"]  剩余 '_aa_a'
r2.exec(s) // null

lastIndex属性」: 指定匹配的开始位置:

const a = /a/y;
a.lastIndex = 2;  // 从2号位置开始匹配
a.exec('wahaha'); // null
a.lastIndex = 3;  // 从3号位置开始匹配
let c = a.exec('wahaha');
c.index;          // 3
a.lastIndex;      // 4

「返回多个匹配」: 一个y修饰符对match方法只能返回第一个匹配,与g修饰符搭配能返回所有匹配。

'a1a2a3'.match(/a\d/y);  // ["a1"]
'a1a2a3'.match(/a\d/gy); // ["a1", "a2", "a3"]

「检查是否使用y修饰符」: 使用sticky属性检查。

const a = /hello\d/y;
a.sticky;     // true

4.5 flags属性

flags属性返回所有正则表达式的修饰符。

/abc/ig.flags;  // 'gi'

5. 正则表达式拓展(ES9)

在正则表达式中,点(.)可以表示任意单个字符,除了两个:用u修饰符解决「四个字节的UTF-16字符」,另一个是行终止符。 「终止符」即表示一行的结束,如下四个字符属于“行终止符”:

  • U+000A 换行符(\n)
  • U+000D 回车符(\r)
  • U+2028 行分隔符(line separator)
  • U+2029 段分隔符(paragraph separator)
/foo.bar/.test('foo\nbar')
// false

上面代码中,因为.不匹配\n,所以正则表达式返回false。 换个醒,可以匹配任意单个字符:

/foo[^]bar/.test('foo\nbar')
// true

ES9引入s修饰符,使得.可以匹配任意单个字符:

/foo.bar/s.test('foo\nbar') // true

这被称为dotAll模式,即点(dot)代表一切字符。所以,正则表达式还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。

const re = /foo.bar/s;
// 另一种写法
// const re = new RegExp('foo.bar', 's');

re.test('foo\nbar') // true
re.dotAll // true
re.flags // 's'

/s修饰符和多行修饰符/m不冲突,两者一起使用的情况下,.匹配所有字符,而^$匹配每一行的行首和行尾。

参考资料

1.MDN 正则表达式 2.W3school JavaScript RegExp 对象

本文分享自微信公众号 - 前端自习课(FE-study),作者:王平安

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【JS】250- 十大排序的算法思路和代码实现

    本文内容包括:(双向)冒泡排序、选择排序、插入排序、快速排序(填坑和交换)、归并排序、桶排序、基数排序、计数排序(优化)、堆排序、希尔排序。大家可以在这里测试代...

    pingan8787
  • 【重温基础】JavaScript 中的高阶函数

    Ps. 晚上加班到快十点,回来赶紧整理整理这篇文章,今天老大给我推荐了一篇文章,我从写技术博客中收获到了什么?- JKnight,感受也是很多,自己也需要慢慢养...

    pingan8787
  • 【CSS】419- 彻底搞懂word-break、word-wrap、white-space

    可以看到,nbsp; 和 </br> 可以正常发挥作用,而连续的空格会被缩减成一个(比如This和is之间的三个空格变成了一个),换行符也全都无效。句子超过一行...

    pingan8787
  • php字符串和0比较,比较都默认转换为0? 原

    if($str==0),字符串和数字比较是否相等, 相当于 把$str 字符串隐性转换为数字,然后再比较,相当于 if( intval($str) == 0 )...

    lilugirl
  • 【Codeforces】1230B - Ania and Minimizing

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    喜欢ctrl的cxk
  • VB.NET 文件上传FTP服务器

    Private Function 上传文件(FTP路径 As String, 文件 As Byte(), FTP用户名 As String, FTP密码 As...

    巴西_prince
  • 聊聊storm client的nimbus.seeds参数

    storm-core-1.1.0-sources.jar!/org/apache/storm/Config.java

    codecraft
  • xss防御

    XSS攻击:跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故...

    听城
  • java 记录对象前后修改的内容(工具类)

      RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。

    陈灬大灬海
  • js去掉字符串前后空格的五种方法

    第一种:循环检查替换 [javascript] //供使用者调用   function trim(s){   return trimRight(trimLeft...

    joshua317

扫码关注云+社区

领取腾讯云代金券