前言
紧接着上次的 js 中的正则表达式 (1), 这一文搁在那很久了的, 本文为初学者学习笔记心得, 适用我这种小白, 并不是什么高大尚的内容, 您将在本文中看到, 如何实现重复字符匹配, 子表达式的使用, 嵌套以及 replace() 方法中圆括号内第二个特殊参数的使用, 欢迎路过的老师多提意见和指正
可以戳后链接 js 中的正则表达式(2)
重复字符匹配
x+: 要想对同一个字符 (或字符集合) 进行多次重复匹配, 只要给这个字符 (或者字符集合) 加上 + 字符作为后缀就可以了的,+ 匹配一个或多个字符 (也就是至少一个, 不匹配零个字符(大于零) 的情况)
示例 1:
- var str = "aaabbb";
- var pattern = /a+/;
- console.log(pattern.test(str)); // true
- console.log(pattern.exec(str)); // aaa
示例 2:
- var str = "itclanCoder itclanCoder itclanCoder"
- var pattern = /(itclanCoder)+/
- console.log(pattern.test(str)) // true
示例 3:
- var str = 283714982423;
- var pattern= /[0-9]+/
- console.log(pattern.test(str)); // true
注意: 在给一个字符集合上 + 后缀的时候, 必需把 + 字符放在这个集合的外面, 比如 [0-9]+ 是正确的, 匹配一个或者多个连续的数字, 而[0-9+] 则不是, 其实后面一个也是一个正确的正则表达式, 只是含义不一样, 它表示的是一个由数字 0 到 9 和 + 构成的字符集合, 它只能匹配一个单个的数字字符或者加号, 而 + 号是一个元字符, 如果需要匹配 + 本身, 就必须要使用它的转义 `\+`
*: 匹配零个或多个字符 (匹配一个可有可无的字符, 也就是与之匹配的字符可以出现零次或多次的情况), 用法与 + 一样, 只要把它放在一个字符(或者一个字符集合) 的后面, 就可以匹配该字符 (或字符集合) 连续出现零次或多次的情况
示例 1:
var str = "川川 随笔川迹 itclanCoder"
var pattern = / 川 */
console.log(pattern.test(str)); // true
+ 与 * 的区别: +: 匹配的是一个或者多个字符(或字符集合), 也就是最少要匹配一次, 至少有一个或者多个匹配, 而 *: 匹配零个或者任意多个字符(或者字符集合), 可以没有匹配 比如下面的两个实例应用区别: 电子邮件的匹配规则 示例 2:
- var str = www .itclanCoder@163.com is my email
- var pattern = /[\w.]+@[\w.]+\.\w+/
- console.log(pattern.exec(str)) // .itclanCoder@163.com
- /*[\w.]+ 表示匹配字符集合 [\w.](也就是字母数字字符, 下划线和.) 的一次或多次重复出现,.itclanCoder 显然符合这一个条件 */
示例 3:
- var str = www .itclanCoder@163.com is my email
- var pattern = /\w+[\w.]*@[\w.]+\.\w+/;
- console.log(pattern.exec(str)); // itclanCoder@163.com
- /*\w+: 负责匹配电子邮件地止里的第一个字符(一个字母数字字符, 但不包括. 字符),[\w.]* 表示匹配电子邮键地止里第一个字符之后,@字符之前的所有字符, 这个部分可以包含零个或多个字母数字字符和. 字符 */
?: 匹配零个或一个字符, 也就是说它只能匹配一个字符 (或字符集合) 的零次或一次出现, 最多不超过一次
应用场合: 如果需要在一段文本里匹配某个特定的字符 (或字符集合) 而该出现字符可能出现, 也可能不出现,? 是最佳的选择
示例 1:
- var str = "http://www.baidu.com and https:www.google.com"
- var pattern = /http[s]?/
- console.log(pattern.exec(str)); // http
- /**
- ?: 在这里的含义是, 前面的一个字符 (s) 要么出现要么不出现, 要么最多出现一次, 也就是 http[s]? 既可以匹配 http, 也可以匹配 https
- */
小结: 问题:
+, 与 * 匹配的字符个数是没有上限的, 无法为它们将匹配的字符个数设定一个最大的值
+ 与 *,? 至少匹配零个或者一个字符, 无法为他们将匹配的字符个数设定一个最小值
如果只是使用 + 和 *, 无法把他们将匹配的字符个数设定为一个精确的数字
{}: 匹配重复次数, 把数值写在双大括号里面, 用于限定次数
示例 1: 匹配重复多个字符 / x{n}/
- var str = "Google";
- var pattern = /o{2}/ // 表示的是模式里前一个字符 (或者字符集合) 必须在所要匹配的文本里连续出现 2 次才算是一个匹配, 如果只匹配了一次, 那么不叫做一个匹配, 匹配会失败
- console.log(pattern.exec(str)) // oo
示例 2: 为重复匹配次数设定一个区间 / x{m,n}/ 匹配 x 字符最少 m 次, 最多 n 次
- var str = "google orange olive";
- var pattern = /o{2,4}/ // 模式匹配, o 最少重复 2 次, 最多重复 4 次
- console.log(pattern.exec(str)); // oo
示例 3: 重复匹配 0 次到 n 次 / x{0,n}/, 匹配字符 x,0 次..n 次
- var str = "itclancoder itclancoder itclancoder"
- var pattern = /i{0,3}/ // 模式匹配 i 字符可以重复 0 次, 1 次, 2 次或者 3 次, 这也明?=={0,1}
- console.log(pattern.exec(str)); // i
示例 4: 匹配至少重复多少次: 给出一个最小的重复次数, 不必给出一个最大值 /{n,}/ 至少重复 n 次, 或者必须重复 n 次或者更多次
- var str = "jjjjbbbbbddddd";
- var pattern = /j{2,}/ // 模式匹配 j 字符至少重复 2 次, 注意它只作用于紧挨着它的前一个字符
- console.log(pattern.exec(str)); // jjjj
贪婪型元字符:*,+,{n,}
懒惰型元字符:*?,+?,{n,}?
什么是子表达式
概念: 对表达式进行分组和归类, 也是更大的表达式的一部分, 把一个表达式划分为一系列子表达式的目的是为了把那些子表达式当做一个独立元素来使用 方式: 子表达式必须用 (和) 括起来, 注意,(左括号和右括号)是元字符, 如果想要匹配本身, 注意转义(和)
示例 1:
- var str = "2018-01-13";
- var pattern = /(20|21)\d{2}/ // (20 |21)\d{2}正确匹配到 2018,\d 表示匹配任何一个数字字符, 也就是 [0-9],{2} 表示的是重复匹配两次, 以 20 或者 21 开头的任何一个 4 位数字将与这个模式匹配
- console.log(pattern.exec(str)); // 2018
子表达式的嵌套
子表达式是允许多层嵌套的, 没有限制, 但是要适可而止, 多重的嵌套子表达式可以构造出强大的正则表达式, 但是由于层层嵌套, 会让正则表达式难以阅读和理解, 但硬骨头始终是要啃的, 如果进行表达式的拆分, 每次只分析和理解一个子表达式, 按照先内后外的原则来进行拆分, 而不是从第一个字符开始一个字符一个字符的去尝试, 也许就会好很多 示例 1: 匹配一个合法的 IP 地止
正则匹配要求:
1. 任何一个 1 位或 2 位数字 (\d{1,2})
2. 任何一个以 1 开头的 3 位数字 (1\d{2})
3. 任何一个以 2 开头, 第 2 位数字在 0~4 之间的 3 位数字 (2[0-4]\d)
4. 任何一个以 25 开头, 第 3 位数字在 0~5 之间的 3 位数字 (25[0-5])
- var str = "12.159.46.240"
- var pattern = /(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))/
- console.log(pattern.exec(str)); // ["12.159.46.24", "46.", "46", "46", undefined, undefined, undefined, "24", "24", undefined, undefined, undefined, undefined, index: 0, input: "12.159.46.240"]
这个模式相当的长而且看着非常繁琐而复杂, 是由众多个子表单时嵌套构成, 4 个子表达式
((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))
, 从左边到右边,(\d{1,2})表示匹配任意一个 1 位或者两位数字 (0-99),(1\d{2}) 表示的是一个以 1 开头的任意三位数 (也就是 100-199),(2[0-4]\d) 表示匹配整数 200-249,(25[0-5])表示的是匹配整数 250-255, 上面的长表达式通过 | 操作符结合成为一个更大的子表达式, 其中含义是只需匹配 4 个子表达式中的任意一个就可以, 而后面的 \. 用来匹配元字符. 本身, 而后面的 {3} 表示需要重复 3 次, 直到最后, 数值范围又重复了一次, 此次过程省略了 \. 用来匹配 IP 地止里的最后一组数字, 通过把 4 组数字的取值范围限制在 0~255 之间, 这个模式就做到了只匹配合法的 IP 地止, 不匹配非法的 Ip 地止
小结: 子表达式非常强大, 也非常灵活, 它是把同一个表达式的各个相关的部分组合在一起从而构成强大的匹配模式, 子表达式必须用 (右括号和左括号) 来定义, 并且子表达式可以多层嵌套使用 用途: 对重复次数元字符的作用对象做出精准的设定和控制, 对 | 操作符的 OR 条件做出准确的定义等
replace()方法第二个参数的特殊字符使用
语法: 待检测字符串对象. replace(正则规则, 要替换的文本或者功能函数),str.replace(pattern,fun);
参数: 圆括号内第一个参数表示正则规则, 第二个参数可以是字符串也可以是函数, 在 str 中查找与 RegExp(pattern)相匹配的子字符串, 第二个参数值或者功能函数执行结果来替换这些子串, 如果 RegExp(pattern)具有全局标志 g, 那么 replace()方法将替换所有匹配的子串, 否则, 它只替换第一个匹配子串 (也就是说默认只会找第一个子串进行返回, 若想全局替换, 则要加 g 修饰符),replace() 中的第二个参数,$ 字符具有特定的含义, 它是从模式匹配得到的字符串将用于替换待检测字符串文本 返回: 返回替换后的新字符串
$$: 把找到的子字符串用一个单独的
$")
- var str = "itclancoder itclancoder";
- var pattern = /o/g;
- console.log(str.replace(pattern,"$$"));//itclanc$der itclanc$der
$&: 使用第一个参数中所给定的子字符串来替换所找到的子字符串, 例如:"itclanCoder itclanCoder".replace(/o/g,"$&"); // itclanCoder itclanCoder
- var str = "itclanCoder itclanCoder";
- var pattern = /o/g;
- console.log(str.replace(pattern,"$&")); //itclanCoder itclanCoder
$: 使用所找到的子字符串之前的文本来替换该子字符串(即处于匹配子串左侧的所有文本), 例如:"itclanCoder itclanCoder".replace(/o/g/,"$");
- var str = "itclanCoder itclanCoder";
- var pattern = /i/g;
- console.log(str.replace(pattern,"$"));//$tclanCoder $tclanCoder
$1,$2,etc: 当第一个参数中包含的正则表达式, 使用小括号进行表达式分组, 则可以实现提取出特定的表达式所匹配的子字符($1 对应第一个小括号对的匹配项,$2 对应第二个小括号对的匹配项, 以此类推): 比如:"Hello world".replace(/(o)(\s)/g,"$1$1$2"); //
- var str = "Hello world";
- var pattern = /(o)(\s)/;
- console.log(str.replace(pattern,"$1$1$2"));// Helloo world
对于 replace(正则规则, 要替换的文本或者功能函数)方法中的第二个参数可以用函数的方式传入, 而不只是一个字符串值, 在这种情况下, 原始字符串中每出现一项匹配的子字符串, 都会执行一次该函数, 并传入所匹配的子字符串, 会使用函数的返回值来替换原子字符: 例如
- // 初始化一个值, 用作计数器
- var count = 0;
- // 声明一个函数, 当每找到一项匹配的子字符串时, 执行该函数, 函数的参数是所匹配的子字符本身
- function replaceWithCount(value) {
- // 计数器加一
- count = count + 1;
- // 将传入的值结合计数器当前的值返回至目标字符串, 替换掉匹配的子字符串
- return value + count
- }
- // 例子
- console.log("itclanCoder itclanCoder".replace(/o/g, replaceWithCount)); // itclanCo1der itclanCo2der
- console.log("itclancoder itclanCoder".replace(/\s/g, replaceWithCount)); // itclanCoder 3itclanCoder, 其中这个 \ s 匹配空白字符, 即空格, tab 制表符, 回车符, 换行符, 换页符
总结:
整篇文章主要是对上节的一个补充, 正则的内容太长了, 容易令人看到想吐, 主要谈到利用 x + 进行重复匹配, 也就是元字符加 (+) 的使用, 以及用 * 匹配零个或多个字符,?: 匹配零个或一个字符, 只能匹配一个字符, 对他们三者做了一个简单的比较, 子表达式的使用, 嵌套, replace()方法中第二个参数特殊字符的使用, 以及作为函数时使用, 而在平时当中, 第二个参数作为函数处理是很常见的, 当然正则是非常强大, 远不止这点皮毛, 反正我个人觉得, 还是挺复杂的, 往往通过正则写起来复杂的, 用面向过程写法, 逻辑更为复杂的, 工具用好了, 就是神器
以下是本篇提点概要
重复字符匹配(x+)
*: 匹配零个或多个字符
+: 匹配的是一个或者多个字符(或字符集合), 也就是最少要匹配一次, 至少有一个或者多个匹配
+, 与 * 一个比较, 以及 +,*,? 三者比较
什么是子表达式(对表达式进行分组和归类, 也是更大的表达式的一部分, 把一个表达式划分为一系列子表达式的目的是为了把那些子表达式当做一个独立元素来使用)
子表达式的嵌套
replace()方法第二个参数的特殊字符使用
来源: https://juejin.im/post/5a7a9837f265da4e865a5776