当前位置:   article > 正文

JavaScript中的正则表达式_js 创建一个正则

js 创建一个正则

前言

JS正则表达式语法大全(非常详细)

js中的正则表达式_wan_da的博客-CSDN博客

JS 正则表达式_js正则表达式_鲨鱼辣椒️面的博客-CSDN博客

JavaScript 正则表达式 | 菜鸟教程

https://www.cnblogs.com/lnlvinso/p/10467941.html

        正则表达式,又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

        正则表达式是一种通用的工具,在 JavaScript、PHP、Java、PythonC++ 等几乎所有的编程语言中都能使用;但是,不同编程语言对正则表达式语法的支持不尽相同,有的编程语言支持所有的语法,有的仅支持一个子集。本节讲到的正则表达式语法适用于 JavaScript

说白了正则表达式就是处理字符串的,我们可以用它来处理一些复杂的字符串

为什么要学习正则表达式

我们直接用一个例子来说明:

  1. //找出这个字符串中的所有数字
  2. var str = 'abc123de45fgh6789qqq111';
  3. //方法1
  4. function findNum(str) {
  5. var tmp = '',
  6. arr = [];
  7. for (var i = 0; i < str.length; i++) {
  8. var cur = str[i];
  9. if (!isNaN(cur)) {
  10. tmp += cur;
  11. } else {
  12. if (tmp) {
  13. arr.push(tmp);
  14. tmp = '';
  15. }
  16. }
  17. }
  18. if (tmp) {
  19. arr.push(tmp)
  20. }
  21. return arr;
  22. }
  23. console.log(findNum(str))
  24. //["123", "45", "6789", "111"]
  25. //方法2 使用正则表达式
  26. var reg = /\d+/g;
  27. console.log(str.match(reg))
  28. // ["123", "45", "6789", "111"]

        通过比较2种方法我们明显看出在对字符串进行处理时,使用正则表达式会简单许多,所以虽然正则表达式看起来像是火星文一样的一堆乱码的东西,但我们还是有必要去学习它的。

一、正则表达式的创建方式

1、通过字面量创建

语法: /正则表达式主体/修饰符(可选)

注意:/....../     以 / 开头,以 / 结尾,中间的内容为正则表达式

 试例:

var reg = /pattern/flags

2、通过实例创建

语法:   new RegExp(pattern,flags(可选))

注意:

  • JS中有自带RegExp构造函数
  • 在 RegExp() 构造函数中使用元字符时,应使用双斜杠。因为通过实例创建会自动加上/.../

参数分析:

  • pattern:正则表达式
  • flags:标识(修饰符)
  • 标识主要包括:
    • 1. i 忽略大小写匹配
    • 2. m 多行匹配,即在到达一行文本末尾时还会继续寻常下一行中是否与正则匹配的项
    • 3. g 全局匹配 正则表达式将匹配目标字符串中所有符合模式的文本,而不是只匹配第一个符合模式的文本。

使用g时,匹配全部字符串,且根据上一次匹配结束的地方开始下一次匹配

不使用g时,匹配部分字符串,且每次都是从起始位置开始匹配

3、字面量创建方式和构造函数创建方式的区别

字面量创建方式不能进行字符串拼接,实例创建方式可以

  1. var regParam = 'cm';
  2. var reg1 = new RegExp(regParam+'1');
  3. var reg2 = /regParam/;
  4. console.log(reg1); // /cm1/
  5. console.log(reg2); // /regParam/

字面量创建方式特殊含义的字符不需要转义,实例创建方式需要转义

  1. var reg1 = new RegExp('\d'); // /d/
  2. var reg2 = new RegExp('\\d') // /\d/
  3. var reg3 = /\d/; // /\d/

二、元字符

        根据正则表达式语法规则,大部分字符仅能够描述自身,这些字符被称为普通字符,如所有的字母、数字等。

        元字符就是拥有特动功能的特殊字符,大部分需要加反斜杠进行标识,以便于普通字符进行区别,而少数元字符,需要加反斜杠,以便转译为普通字符使用。JavaScript 正则表达式支持的元字符如下所示。

1、代表特殊含义的元字符

\d :  0-9之间的任意一个数字  \d只占一个位置

\D : 除了\d
\w :  数字,字母 ,下划线  0-9  a-z  A-Z  _

\W : 除了\w
\s :  空格或者空白等
\S : 除了\s

\b : 匹配边界 字符串的开头和结尾 空格的两边都是边界 => 不占用字符串位数

\B:匹配非单词边界

\0:查找 NUL字符

\f:查找换页符

\r:查找回车符

\t:查找制表符

\v:查找垂直制表符

\n : 匹配换行符
 . : 除了\n之外的任意一个字符,查找单个字符,除了换行和行结束符
 \ : 转义字符,绝大部分字符加反斜杠还表示字符本身
 | : 或者  or
() : 分组

\xdd:查找以八进制数 dd 规定ASCII 编码的字符

\xdd:查找以十六进制数 dd 规定ASCII 编码的字符

\uxxxx:查找以十六进制 xxxx规定的 Unicode 字符

        表示字符的方法有多种,除了可以直接使用字符本身外,还可以使用 ASCII 编码或者 Unicode 编码来表示。ASCII编码对照表

示例1:

  • 下面使用 ASCII 编码定义正则表达式直接量。
  • 由于字母 a 的 ASCII 编码为 97,被转换为十六进制数值后为 61,因此如果要匹配字符 a,就应该在前面添加“\x”前缀,以提示它为 ASCII 编码。
  1. var r = /\x61/;
  2. var s = "JavaScript";
  3. var a = s.match(r);
  4. console.log(a); //[ 'a', index: 1, input: 'JavaScript', groups: undefined ]

示例2:

  •  除了十六进制外,还可以直接使用八进制数值表示字符。
  • 使用十六进制需要添加“\x”前缀,主要是为了避免语义混淆,而八进制则不需要添加前缀。
  1. var r = /\141/;
  2. var s = "JavaScript";
  3. var a = s.match(r);
  4. console.log(a); //[ 'a', index: 1, input: 'JavaScript', groups: undefined ]

示例3:

  • ASCII 编码只能够匹配有限的单字节字符,使用 Unicode 编码可以表示双字节字符。Unicode 编码方式:“\u”前缀加上 4 位十六进制值。
  1. var r = /\u0061/i;
  2. var s = "JavaScript";
  3. var a = s.match(r);
  4. console.log(a); //[ 'a', index: 1, input: 'JavaScript', groups: undefined ]

2、代表边界的量词元字符

边界就是确定匹配模式的位置,如字符串的头部或尾部,具体说明如表所示。

 ^ : 限定开始位置 => 本身不占位置
 $ : 限定结束位置 => 本身不占位置

下面代码演示如何使用边界量词。先定义字符串:

    var s = "how are you"

1) 匹配最后一个单词

  1. var s = 'how are you'
  2. var r = /\w+$/;
  3. var a = s.match(r); //[ 'you', index: 8, input: 'how are you', groups: undefined ]

2) 匹配第一个单词

  1. var s = 'how are you'
  2. var r = /^\w+/;
  3. var a = s.match(r); //[ 'how', index: 0, input: 'how are you', groups: undefined ]

3) 匹配每一个单词

  1. var s = 'how are you'
  2. var r = /\w+/g;
  3. var a = s.match(r); //返回数组["how","are","you"]

3、代表次数的量词元字符

* :  匹配 0  到多个,等价于X{0,}  至少匹配字符串末尾的空字符串
+ :  至少匹配 1 个,等价于X{1,}
? :  匹配最多 1 个等价于X{0,1}
{n} :  正好n次;
{n,} :  n到多次
{n,m} :  n次到m次

量词出现在元字符后面 如\d+,限定出现在前面的元字符的次数

举个例子:

  1. var str = '0123456789';
  2. var reg = /\d{2}/; //非全局匹配
  3. var res = str.match(reg);
  4. console.log(res) //[ '01', index: 0, input: '0123456789', groups: undefined ]
  5. var str =' 我是空格君 ';
  6. var reg = /^\s+|\s+$/g; //匹配开头结尾空格,全局匹配 模式应用于所有字符串,而非在找到第一个匹配项时停止
  7. console.log('('+str+')'); //( 我是空格君 )
  8. var res = str.replace(reg,'');
  9. console.log('('+res+')'); //(我是空格君)

三、正则中的( )和[ ]

1、[  ]  描述字符范围

        在正则表达式语法中,方括号表示字符范围。在方括号中可以包含多个字符,表示匹配其中任意一个字符。如果多个字符的编码顺序是连续的,可以仅指定开头和结尾字符,省略中间字符,仅使用连字符 - 表示。如果在方括号内添加脱字符 ^ 前缀,还可以表示范围之外的字符。例如:

如果不加量词,默认为一个

  • [abc]:查找方括号内任意一个字符。
  • [^abc]:查找不在方括号内的字符。
  • [0-9]:查找从 0 至 9 范围内的数字,即查找数字。
  • [a-z]:查找从小写 a 到小写 z 范围内的字符,即查找小写字母。
  • [A-Z]:查找从大写 A 到大写 Z 范围内的字符,即查找大写字母。
  • [A-z]:查找从大写 A 到小写 z 范围内的字符,即所有大小写的字母。

在中括号内不要有空格,否则会误解为还要匹配空格。

示例1:

        字符范围遵循字符编码的顺序进行匹配。如果将要匹配的字符恰好在字符编码表中特定区域内,就可以使用这种方式表示。

  • 如果匹配任意 ASCII 字符:
    var r = /[\u0000-\u007F]/g;
  • 如果匹配任意大小写字母和数字
    var r = /[a-zA-Z0-9]/g;
  • 使用 Unicode 编码设计,匹配数字:
    var r = /[\u0030-\u0039]/g;
  •  使用下面字符模式可以匹配任意大写字母:
    var r = /[\u0041-\u004A]/g;
  • 使用下面字符模式可以匹配任意小写字母:
    var r = /[\u0061-\u007A]/g;

示例2:

在字符范围内可以混用各种字符模式。

  1. var s = "abcdez"; //字符串直接量
  2. var r = /[abce-z]/g; //字符a、b、c,以及从e~z之间的任意字符
  3. var a = s.match(r);
  4. console.log(a); //返回数组["a","b","c","e","z"]

示例3

字符范围可以组合使用,以便设计更灵活的匹配模式。

  1. var s = "abc4 abd6 abe3 abf1 abg7"; //字符串直接量
  2. var r = /ab[c-g][1-7]/g; //前两个字符为ab,第三个字符为从c到g,第四个字符为1~7的任意数字
  3. var a = s.match(r);
  4. console.log(a); //返回数组["abc4","abd6","abe3","abf1","abg7"]

一般[]中的字符没有特殊含义

如+就表示+,. 就表示 .  但是像\w这样的还是有特殊含义的

  1. var str1 = 'abc';
  2. var str2 = 'dbc';
  3. var str3 = '.bc';
  4. var reg = /[ab.]bc/; //此时的.就表示.
  5. console.log(reg.test(str1)); //true
  6. console.log(reg.test(str2)); //false
  7. console.log(reg.test(str3)); //true

[]中,不会出现两位数

[12]表示1或者2   不过[0-9]这样的表示0到9   [a-z]表示a到z

例如:匹配从18到65年龄段所有的人

这样写对吗???

  1. var reg = /[18-65]/; // 这样写对么
  2. console.log(reg.test('50'));

SyntaxError: Invalid regular expression: /[18-65]/: Range out of order in character class

实际上我们匹配这个18-65年龄段的正则我们要拆开来匹配 我们拆成3部分来匹配

  • 18-19     20-59      60-65
  1. var reg = /(18|19)|([2-5]\d)|(6[0-5])/;
  2. console.log(reg.test('50')); //true

2、( )小括号

  • ()的提高优先级功能:凡是有|出现的时候,我们一定要注意是否有必要加上()来提高优先级;

  • ()的分组 

    • 分组: 只要正则中出现了小括号那么就会形成一份分组 只要有分组,exec(match)和replace中的结果就会发生改变(后边的正则方法中再说)

    • 分组的引用(重复子项) : 只要在正则中出现了括号就会形成一个分组,我们可以通过\n (n是数字代表的是第几个分组)来引用这个分组,第一个小分组我们可以用\1来表示

  • 当我们加( )只是为了提高优先级而不想捕获小分组时,可以在()中加?:来取消分组的捕获
  1. var str = 'aaaefgccc';
  2. var reg = /(a+)(?:[e-h]+)(c*)/;
  3. var res =reg.exec(str);
  4. console.log(res)
  5. //只捕获第一个和第三个小分组的内容

四、选择匹配

        选择匹配类似于 JavaScript 的逻辑与运算,使用竖线|描述,表示在两个子模式的匹配结果中任选一个。例如:

1、匹配任意数字或字母

    var r = /\w+|\d+/;

2、可以定义多重选择模式。设计方法:在多个子模式之间加入选择操作符。

    var r = /(abc)|(efg)|(123)|(456)/;

示例

        设计对提交的表单字符串进行敏感词过滤。先设计一个敏感词列表,然后使用竖线把它们连接在一起,定义选择匹配模式,最后使用字符串的 replace() 方法把所有敏感字符替换为可以显示的编码格式。代码如下:

  1. var s = '<meta charset="utf-8">'; //待过滤的表单提交信息
  2. var r = /\'|\"|\<|\>/gi; //过滤敏感字符的正则表达式
  3. function f() { //替换函数
  4. 把敏感字符替换为对应的网页显示的编码格式
  5. return "&#" + arguments[0].charCodeAt(0) + ";";
  6. }
  7. var a =s.replace(r,f); //执行过滤替换
  8. document.write(a); //在网页中显示正常的字符信息
  9. console.log(a);

五、重复匹配

        在正则表达式语法中,定义了一组重复类量词,如表所示。它们定义了重复匹配字符的确数或约数。

示例 

下面结合示例进行演示说明,先设计一个字符串:

    var s = "ggle gogle google gooogle goooogle gooooogle goooooogle gooooooogle goooooooogle";

1) 如果仅匹配单词 ggle 和 gogle,可以设计:

  1. var r = /go?gle/g;
  2. var a = s.match(r); //[ 'ggle', 'gogle' ]

量词?表示前面字符或子表达式为可有可无,等效于:

  1. var r = /go{0,1}gle/g;
  2. var a = s.match(r); //[ 'ggle', 'gogle' ]

2) 如果匹配第 4 个单词 gooogle,可以设计:

  1. var r = /go{3}gle/g;
  2. var a = s.match(r); //[ 'gooogle' ]

等效于:

  1. var r = /gooogle/g;
  2. var a = s.match(r); //[ 'gooogle' ]

3) 如果匹配第 4 个到第 6 个之间的单词,可以设计:

  1. var r = /go{3,5}gle/g;
  2. var a = s.match(r); //[ 'gooogle', 'goooogle', 'gooooogle' ]

4) 如果匹配所有单词,可以设计:

  1. var r = /go*gle/g;
  2. var a = s.match(r);

量词*表示前面字符或表达式可以不出现,或者重复出现任意多次。等效于:

  1. var r = /go(0,)gle/g;
  2. var a = s.match(r);

5) 如果匹配包含字符“o”的所有词,可以设计:

  1. var r = /go+gle/g;
  2. var a = s.match(r);

量词+表示前面字符或子表达式至少出现 1 次,最多重复次数不限。等效于:

  1. var r = /go{1,}gle/g;
  2. var a = s.match(r);

重复类量词总是出现在它们所作用的字符或子表达式后面。如果想作用于多个字符,需要使用小括号把它们包裹在一起形成一个子表达式。

六、惰性匹配与贪婪匹配

重复类量词都具有贪婪性,在条件允许的前提下,会匹配尽可能多的字符。

  • ?、{n} 和 {n,m} 重复类具有弱贪婪性,表现为贪婪的有限性。
  • *、+ 和 {n,} 重复类具有强贪婪性,表现为贪婪的无限性。
  • 贪婪性

    所谓的贪婪性就是正则在捕获时,每一次会尽可能多的去捕获符合条件的内容。
    如果我们想尽可能的少的去捕获符合条件的字符串的话,可以在量词元字符后加?

  • 懒惰性

    懒惰性则是正则在成功捕获一次后不管后边的字符串有没有符合条件的都不再捕获。
    如果想捕获目标中所有符合条件的字符串的话,我们可以用标识符g来标明是全局捕获

  1. var str = '123aaa456';
  2. var reg = /\d+/; //只捕获一次,一次尽可能多的捕获
  3. var res = str.match(reg)
  4. console.log(res)
  5. // ["123", index: 0, input: "123aaa456"]
  6. reg = /\d+?/g; //解决贪婪性、懒惰性
  7. res = str.match(reg)
  8. console.log(res)
  9. // ["1", "2", "3", "4", "5", "6"]

示例1

        越是排在左侧的重复类量词匹配优先级越高。下面示例显示当多个重复类量词同时满足条件时,会在保证右侧重复类量词最低匹配次数基础上,使最左侧的重复类量词尽可能占有所有字符。

  1. var s = "<html><head><title></title></head><body></body></html>";
  2. var r = /(<.*>)(<.*>)/;
  3. var a = s.match(r);
  4. console.log(a);
  5. console.log(a[0]); //左侧表达式匹配“<html><head><title></title></head><body></body></html>”
  6. console.log(a[2]); //右侧表达式匹配“</html>”

        与贪婪匹配相反,惰性匹配将遵循另一种算法:在满足条件的前提下,尽可能少的匹配字符。定义惰性匹配的方法:在重复类量词后面添加问号?限制词。贪婪匹配体现了最大化匹配原则,惰性匹配则体现最小化匹配原则。

  1. var s = "<html><head><title></title></head><body></body></html>";
  2. var r = /<.*?>/
  3. var a = s.match(r); //返回单个元素数组["<html>"]

        在上面示例中,对于正则表达式 /<.*?>/ 来说,其中 .*? 表示匹配任何字符(除了换行符)零次或多次,但是尽可能少地匹配,这被称为非贪婪匹配,它可以返回匹配字符串 "<>",但是为了能够确保匹配条件成立,在执行中还是匹配了带有 4 个字符的字符串“html”。惰性取值不能够以违反模式限定的条件而返回,除非没有找到符合条件的字符串,否则必须满足它。

针对 6 种重复类惰性匹配的简单描述如下:

  • {n,m}?:尽量匹配 n 次,但是为了满足限定条件也可能最多重复 m 次。
  • {n}?:尽量匹配 n 次。
  • {n,}?:尽量匹配 n 次,但是为了满足限定条件也可能匹配任意次。
  • ??:尽量匹配,但是为了满足限定条件也可能最多匹配 1 次,相当于 {0,1}?。
  • +?:尽量匹配 1 次,但是为了满足限定条件也可能匹配任意次,相当于 {1,}?。
  • *? :尽量不匹配,但是为了满足限定条件也可能匹配任意次,相当于 {0,}?。

七、声明词量

声明表示条件的意思。声明词量包括正向声明和反向声明两种模式。

1、正向声明

指定匹配模式后面的字符必须被匹配,但又不返回这些字符。语法格式如下:

匹配模式 (?= 匹配条件)

声明包含在小括号内,它不是分组,因此作为子表达式。

下面代码定义一个正向声明的匹配模式。

  1. var s = "one : 1; two= 2";
  2. var r = /\w*(?==)/; //使用正前向声明,指定执行匹配必须满足的条件
  3. var a = s.match(r); //返回数组[ 'two', index: 9, input: 'one : 1; two= 2', groups: undefined ]

        在上面示例中,通过?= =锚定条件,指定只有在 \w* 所能够匹配的字符后面跟随一个等号字符,才能够执行 \w* 匹配。所以,最后匹配的字符串“two”,而不是字符串“one”

2、反向声明

与正向声明匹配相反,指定接下来的字符都不必被匹配。语法格式如下:

匹配模式(?! 匹配条件)

下面代码定义一个反向声明的匹配模式。

  1. var s = "one : 1; two= 2";
  2. var r = /\w*(?!=)/; //使用正前向声明,指定执行匹配必须满足的条件
  3. var a = s.match(r); //返回数组[ 'one', index: 0, input: 'one : 1; two= 2', groups: undefined ]

        在上面示例中,通过?!=锚定条件,指定只有在“\w*”所能够匹配的字符后面不跟随一个等号字符,才能够执行 \w*匹配。所以,最后匹配的是字符串“one”,而不是字符串“two”。

八、子表达式

子表达式:用()包围的就是子表达式

        使用小括号可以对字符模式进行任意分组,在小括号内的字符串表示子表达式,也称为子模式。子表达式具有独立的匹配功能,保存独立的匹配结果;同时,小括号后的量词将会作用于整个子表达式。

        通过分组可以在一个完整的字符模式中定义一个或多个子模式。当正则表达式成功地匹配目标字符串后,也可以从目标字符串中抽出与子模式相匹配的子内容。

示例

在下面代码中,不仅能匹配出每个变量声明,同时还抽出每个变量及其值。

  1. var s = "ab=21, bc=45, cd=43";
  2. var r = /(\w+)=(\d*)/g;
  3. var a = s.match(r);
  4. console.log(a); //[ 'ab=21', 'bc=45', 'cd=43' ]

九、反向引用

反向引用的子表达式匹配的字符内容和字符数量必须和被引用的子表达式所匹配的字符内容和字符数量一致,否则返回null

子表达式:用()包围的就是子表达式

  •  str = "((/d)(/w))"
  • 第一个子表达式:((\d)(\w))
  • 第二个子表达式:(\d)
  • 第三个子表达式:(\w)
  • 子表达式:以第一个出现的 ( 为第一个表达式

捕获:将匹配到的子表达式保存在RegExp对象中

  • RegExp.$1:保存第一个子表达式
  • RegExp.$2:保存第二个子表达式
  • RegExp.$3:保存第三个子表达式

反向引用:调用捕获到的值

  • \1:指向RegExp.$1
  • \2:指向RegExp.$2
  • \n:指向RegExp.$n

在字符模式中,后面的字符可以引用前面的子表达式。实现方法如下:

\数字

        数字指定了子表达式在字符模式中的顺序。如“\1”引用的是第 1 个子表达式,“\2”引用的是第 2 个子表达式。

示例1

匹配连续相同的三个数字

  1. var str = 'ooo111ooo222ooo333ooo123';
  2. var reg = /(\d)\1\1/g;
  3. var result = str.match(reg);
  4. console.log(result); //[ '111', '222', '333' ]

示例2

匹配类型为abab的数字

  1. var str = 'ooo1212ooo2323ooo3434ooo1234';
  2. var reg = /(\d)(\d)\1\2/g;// \d匹配数字,\1对应的是第一个表达式(\d),\2对应的是第二个表达式(\d),g是全局匹配
  3. var result = str.match(reg);
  4. console.log(result); //[ '1212', '2323', '3434' ]

实例3

匹配标签内的内容

  1. var str = 'ooo<div>hello world!</div>234';
  2. var reg = /<(\w+).*<\/?\1>/g;
  3. var result = str.match(reg);
  4. console.log(result); //[ '<div>hello world!</div>' ]

 分析

  •  \w:  查找字母、数字、下划线
  •  \w+:  匹配查找至少一个\w的字符串
  • .:  查找单个字符除了换行符和行结束符
  • .*:  匹配查找至少零个.的字符串
  • \/:  因为/为特殊字符,所以需要用转义符\
  • \1:  反向引用(\w+)

示例4

        由于子表达式可以相互嵌套,它们的顺序将根据左括号的顺序来确定。例如,下面示例定义匹配模式包含多个子表达式。

  1. var s = "abc";
  2. var r = /(a(b(c)))/;
  3. var a = s.match(r);
  4. console.log(a); //[ 'abc', 'abc', 'bc', 'c', index: 0, input: 'abc', groups: undefined ]

十、禁止引用

        反向引用会占用一定的系统资源,在较长的正则表达式中,反向引用会降低匹配速度。如果分组仅仅是为了方便操作,可以禁止反向引用。

实现方法:在左括号的后面加上一个问号和冒号。

  1. var s1 = "abc";
  2. var r = /(?:\w+?)|(?:\w+)|(?:\d*)/g;
  3. console.log(s1.match(r)); //[ 'a', 'b', 'c', '' ]

这段代码中的正则表达式 /(?:\w+?)|(?:\w+)|(?:\d*)/g 包含了三个非捕获组:

  1. (?:\w+?): 匹配一个或多个任意字母或数字,使用非贪婪模式(即尽可能短地匹配),但不捕获这个组。
  2. (?:\w+): 匹配一个或多个任意字母或数字,不使用非贪婪模式,但不捕获这个组。
  3. (?:\d*): 匹配零个或多个数字,不捕获这个组。

        在字符串 s1 中,所有字符都是字母,因此正则表达式的第一个和第二个非捕获组都会匹配到相应的字符。第三个非捕获组会匹配到零个数字,因为 s1 中不包含任何数字。

        在全局匹配模式下,当正则表达式无法从前面的匹配中找到符合规则的子串时,它会尝试匹配一个空字符串。在这个例子中,正则表达式在匹配完字符串 s1 后,仍然可以尝试在字符串的末尾位置匹配一个空字符串,因此它匹配到了一个空字符串。

        因此,console.log(s1.match(r)) 输出了一个包含四个元素的数组 ['a', 'b', 'c', ''],其中前三个元素是匹配到的字母字符,最后一个元素是匹配到的空字符串。

十一、正则运算符的优先级

正则运算符的优先级从高到低如下:

  1. \(转义符):用于转义元字符或特殊字符,例如 \. 表示匹配点号(.),而不是任意字符。
  2. ()(圆括号):用于分组和捕获,例如 (abc)+ 表示匹配一个或多个连续的 "abc" 字符串。
  3. [](字符集合):用于匹配一个字符集合中的任意一个字符,例如 [abc] 表示匹配字符 "a"、"b" 或 "c" 中的任意一个。
  4. *+?{n}{n,}{n,m}(量词):用于指定前面的模式出现的次数,例如 a+ 表示匹配一个或多个连续的字符 "a"。
  5. ^$(锚点):用于匹配字符串的开头和结尾,例如 ^abc 表示匹配以 "abc" 开头的字符串。
  6. |(分支):用于指定多个模式中的任意一个匹配,例如 a|b 表示匹配字符 "a" 或 "b"。
  7. .(点号):用于匹配除换行符外的任意一个字符。

需要注意的是,正则表达式的优先级并不总是需要关注,因为可以使用圆括号来明确指定各部分的优先级。

  1. 字符具有高于替换运算符的优先级,一般用 | 的时候,为了提高 | 的优先级,我们常用()来提高优先级
  2. 如: 匹配 food或者foot的时候 reg = /foo(t|d)/ 这样来匹配

十二、正则表达式常用属性和方法

1、常用方法

1.1 reg.test(str)

用来验证字符串是否符合正则 符合返回true 否则返回false

  1. var str = 'abc';
  2. var reg = /\w+/;
  3. console.log(reg.test(str)); //true

1.2 reg.exec(str)

用来捕获符合规则的字符串

  1. // 创建一个正则表达式对象,用于匹配数字
  2. const reg = /\d+/g;
  3. // 匹配字符串中的第一个数字
  4. const str = "abc123def456ghi789";
  5. const result1 = reg.exec(str);
  6. console.log(result1); // 输出 ["123", index: 3, input: "abc123def456ghi789", groups: undefined]
  7. // 继续匹配字符串中的下一个数字
  8. const result2 = reg.exec(str);
  9. console.log(result2); // 输出 ["456", index: 9, input: "abc123def456ghi789", groups: undefined]
  10. // 重新设置正则表达式的lastIndex属性为0,从头开始匹配
  11. reg.lastIndex = 0;
  12. const result3 = reg.exec(str);
  13. console.log(result3); // 输出 ["123", index: 3, input: "abc123def456ghi789", groups: undefined]

         在上面的例子中,我们首先创建了一个正则表达式对象 /\d+/ ,用于匹配字符串中的数字。然后我们使用 reg.exec(str) 方法来执行匹配,其中 str 是要匹配的字符串。第一次执行匹配时,返回了匹配到的第一个数字 "123",以及该结果的相关信息(index表示匹配到的字符串在原始字符串中的位置,input表示原始字符串,groups表示匹配到的具名组)。接着我们再次调用 reg.exec(str) 方法,返回了匹配到的下一个数字 "456",以及相关信息。最后我们将 reg.lastIndex 属性设置为0,重新从字符串头开始匹配,得到了和第一次匹配相同的结果。

exec的捕获还受分组()的影响 

  1. var str = '2017-01-05';
  2. var reg = /-(\d+)/g
  3. // ["-01", "01", index: 4, input: "2017-01-05"]
  4. "-01" : 正则捕获到的内容
  5. "01" : 捕获到的字符串中的小分组中的内容

1.3 str.match(reg) 

        是 JavaScript 字符串对象的方法之一,用于在字符串中执行正则表达式匹配。该方法返回一个数组,其中包含匹配到的所有结果以及这些结果的相关信息,如果没有找到匹配项,则返回 null。

正则表达式不加g相当于exec()方法

  1. // 创建一个正则表达式对象,用于匹配数字
  2. const reg = /\d+/;
  3. // 在字符串中匹配所有数字
  4. const str = "abc123def456";
  5. const result = str.match(reg);
  6. console.log(result); // 输出 [ '123', index: 3, input: 'abc123def456', groups: undefined ]
  7. // 在字符串中匹配所有非字母字符
  8. const reg2 = /[^a-zA-Z]+/g;
  9. const result2 = str.match(reg2);
  10. console.log(result2); // 输出 ["123", "456"]
  11. // 匹配不存在的结果,返回 null
  12. const reg3 = /xyz/;
  13. const result3 = str.match(reg3);
  14. console.log(result3); // 输出 null

        在上面的例子中,我们首先创建了一个正则表达式对象 /\d+/,用于匹配字符串中的数字。接着我们使用 str.match(reg) 方法来执行匹配,其中 str 是要匹配的字符串,reg 是要用来匹配的正则表达式。第一次执行匹配时,返回了一个包含匹配到的[ '123', index: 3, input: 'abc123def456', groups: undefined ] 的数组。接着我们创建了另一个正则表达式对象 /[^a-zA-Z]+/g,用于匹配字符串中的所有非字母字符。在执行 str.match(reg2) 方法后,返回了一个包含匹配到的所有非字母字符的数组,即 "123" 和 "456"。最后,我们创建了一个正则表达式对象 /xyz/,用于匹配在字符串中不存在的结果,执行 str.match(reg3) 后返回了 null

1.4 str.replace()

写法1:str.replace(reg,newStr);

        具体来说,我们可以在 str.replace() 方法的第一个参数中传入一个正则表达式对象,然后使用第二个参数来指定要替换成的字符串。如果正则表达式中使用了分组,我们还可以在第二个参数中使用 $1$2$3 等来引用分组匹配到的内容

  1. const str = "The quick brown fox jumps over the lazy dog";
  2. const reg = /fox/i; // 忽略大小写匹配 "fox"
  3. const newStr = str.replace(reg, "cat");
  4. console.log(newStr); // 输出 "The quick brown cat jumps over the lazy dog"
  5. const reg2 = /(\w+) (\w+)/ig; // 匹配字符串中的两个单词
  6. const newStr2 = str.replace(reg2, "$2 $1");
  7. console.log(newStr2); // 输出 "quick The fox brown jumps over lazy the dog"

        在上面的例子中,我们首先创建了一个正则表达式对象 /fox/i,用于匹配字符串中的单词 "fox",并忽略大小写。接着,我们使用 str.replace() 方法来执行替换操作,将字符串中匹配到的单词 "fox" 替换成了 "cat"。

        接下来,我们创建了另一个正则表达式对象 /(\w+) (\w+)/ig,用于匹配字符串中的两个单词。在执行 str.replace() 方法时,我们使用了 $2 $1 作为第二个参数,表示将匹配到的第二个单词和第一个单词交换位置,从而得到了 "quick The fox brown jumps over lazy the dog" 这个新的字符串。

写法2:str.replace(reg,fn);

  1. var str = '2017-01-06';
  2. str = str.replace(/-\d+/g,function(){
  3. console.log(arguments)
  4. })
  5. // [Arguments] { '0': '-01', '1': 4, '2': '2017-01-06' }
  6. // [Arguments] { '0': '-06', '1': 7, '2': '2017-01-06' }

2、常用属性

2.1  lastIndex

则表达式对象的属性,表示下一次匹配开始的索引位置

        当使用 exec()test() 方法进行匹配时,lastIndex 属性会被更新为匹配的最后一个字符的下一个位置。这意味着,下一次调用 exec()test() 方法时,会从 lastIndex 属性的值开始继续匹配。

        如果正则表达式中不包含全局标志(g),那么 lastIndex 属性将始终为 0,因为每次匹配都从字符串的开头开始。

  1. const reg = /a/g;
  2. console.log(reg.lastIndex); // 0
  3. reg.test("abc");
  4. console.log(reg.lastIndex); // 1
  5. reg.test("abc");
  6. console.log(reg.lastIndex); // 0
  7. reg.test("abc");
  8. console.log(reg.lastIndex); // 1
  9. reg.test("abc");
  10. console.log(reg.lastIndex); // 0

        在上面的示例中,我们创建了一个匹配字母 "a" 的正则表达式,并使用 test() 方法进行匹配。由于正则表达式包含全局标志,因此 lastIndex 属性会被更新为每次匹配的最后一个字符的下一个位置。当 lastIndex 属性的值为 0 时,表示下一次匹配将从字符串的开头开始 

十三、正则表达式匹配原理

1、JS中正则表达式为什么总会在字符串末尾匹配到一个空字符

        JavaScript中的正则表达式在匹配字符串时,会从字符串的起始位置开始匹配,直到匹配到一个符合规则的子字符串,或者匹配到字符串的末尾。如果正则表达式没有匹配到任何符合规则的子字符串,那么它会在字符串的末尾匹配到一个空字符,这是正则表达式匹配的默认行为。

        这种行为是因为正则表达式中的某些元字符和量词可能会导致匹配到空字符,比如*?{0,1}。当这些元字符和量词被应用到一个没有字符的位置时,它们会匹配到一个空字符,从而使正则表达式匹配到了字符串的末尾。

2、案例一

  1. var s = ' hello world ';
  2. var r = /^\s+|\s+$/g;
  3. console.log(s.match(r)); //[ ' ', ' ' ]

^\s+|\s+$这个正则中包含了^,$,'|'前面两个匹配的是位置,也就是一个是匹配的是开始位置,另外一个匹配的是结束位置,然后中间的|,代表的是正则表达式中的分支条件,就指的是有几种匹配规则,从正则表达式上上分析第一种规则是匹配开始位置后面是空格的内容,另一种匹配规则是匹配空格到结束位置,当正则表达式在匹配文本时,他首先匹配的是开始位置0,然后发现开始位置后面跟随空格,然后匹配第一种规则,此时匹配到了位置1,但是他发现匹配内容并没有结束,它会从匹配第一次的位置处继续往后匹配,发现有满足第二个规则的内容,从位置12的地方又开始进行匹配,结束为止是位置13,所以匹配了两条。

3、案例二

  1. var s1 = '556';
  2. var r1 = /5*$/g;
  3. console.log(s1.match(r1)); //[ '' ]

        这段代码中的正则表达式 /5*$/g 仍然表示匹配以 0 个或多个数字 5 结尾的子串。在字符串 s1 中,只有以一个或多个数字 5 结尾的子串符合这个模式,即字符串 s1 本身,因为它以数字 5 结尾。

        然而,当你执行 s1.match(r1) 时,它返回了一个包含一个元素的数组 [''],其中元素为一个空字符串。这是因为在全局匹配模式下,当正则表达式无法再从前面的匹配中找到符合规则的子串时,它会尝试匹配一个空字符串。在这个例子中,正则表达式在匹配完字符串 s1 后,仍然可以尝试在字符串的末尾位置匹配一个空字符串,因此它匹配到了一个空字符串。

        因此,console.log(s1.match(r1)) 输出了一个包含一个元素的数组 [''],其中元素为匹配到的空字符串。

4、案例三

  1. var s1 = "abc";
  2. var r = /(a)|([ab])|([abc])/g;
  3. console.log(s1.match(r));
  4. var match;
  5. while ((match = r.exec(s1)) !== null) {
  6. console.log(match);
  7. console.log("Matched substring: " + match[0]);
  8. console.log(match[0]);
  9. console.log(match.index);
  10. console.log(match.input);
  11. console.log(match.groups);
  12. if (match[1]) {
  13. console.log("Matched by group 1: " + match[1]);
  14. } else if (match[2]) {
  15. console.log("Matched by group 2: " + match[2]);
  16. } else if (match[3]) {
  17. console.log("Matched by group 3: " + match[3]);
  18. }
  19. console.log('=================================');
  20. }
  21. /*
  22. [ 'a', 'b', 'c' ]
  23. [
  24. 'a',
  25. 'a',
  26. undefined,
  27. undefined,
  28. index: 0,
  29. input: 'abc',
  30. groups: undefined
  31. ]
  32. Matched substring: a
  33. a
  34. 0
  35. abc
  36. undefined
  37. Matched by group 1: a
  38. =================================
  39. [
  40. 'b',
  41. undefined,
  42. 'b',
  43. undefined,
  44. index: 1,
  45. input: 'abc',
  46. groups: undefined
  47. ]
  48. Matched substring: b
  49. b
  50. 1
  51. abc
  52. undefined
  53. Matched by group 2: b
  54. =================================
  55. [
  56. 'c',
  57. undefined,
  58. undefined,
  59. 'c',
  60. index: 2,
  61. input: 'abc',
  62. groups: undefined
  63. ]
  64. Matched substring: c
  65. c
  66. 2
  67. abc
  68. undefined
  69. Matched by group 3: c
  70. =================================
  71. */

    match = pattern.exec(str)) !== null 是一个条件表达式,用于在每次循环中判断 exec() 方法是否返回了匹配结果。

    pattern.exec(str) 表示调用正则表达式对象 patternexec() 方法,用于在字符串 str 中查找符合正则表达式的子串,并返回匹配结果。如果找到了匹配的子串,则返回一个数组,包含了匹配到的子串以及其位置等信息。如果没有找到匹配的子串,则返回 null

    !== null 表示不等于 null,即 match 不是 null。在这个条件表达式中,我们将 exec() 方法返回的结果赋值给变量 match,并将其与 null 进行比较。如果 match 不是 null,则表示 exec() 方法成功匹配了一个子串,条件表达式的值为 true。否则,表示 exec() 方法已经匹配完了所有的子串,条件表达式的值为 false

        在循环中使用条件表达式可以实现逐个匹配字符串中的子串。在每次循环中,先调用 exec() 方法来查找下一个匹配结果,然后将其赋值给变量 match。如果匹配成功,则执行相应的代码;如果匹配失败,则循环结束。

        对于这个表达式来说,确实存在运算符优先级的问题。在这个表达式中,!== 的优先级高于 =,所以表达式的执行顺序是先执行 !==,再执行 =。但是,在这个表达式中,由于使用了括号,导致先执行了赋值操作,再进行不等于比较。所以实际上,这个表达式的执行顺序并不会受到优先级的影响,而是先执行赋值操作,然后再执行不等于比较。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/781626
推荐阅读