学习正则表达式的时候, 可以说正则并不是很难, 但是就是老记不住语法规则, 相信大家跟我也有同样的发现吧, 但是没办法, 需要耐心的东西只能多啃几遍了.
正则表达式的作用
数据验证.
复杂的字符串搜寻, 替换.
基于模式匹配从字符串中提取子字符串.
概述
正则表达式包括普通字符 (例如, a 到 z 之间的字母) 和特殊字符(称为 "元字符").
若要匹配这些特殊字符, 必须首先转义字符, 即, 在字符前面加反斜杠字符 \**.
例如, 若要搜索 "+" 文本字符, 可使用表达式 \+.
但是大多数 特殊字符 在中括号表达式内出现时失去本来的意义, 并恢复为普通字符.
构造函数
可使用字面量也可以用内置的构造函数:
- var regex = new RegExp('xyz', 'i');
- var regex = new RegExp(/xyz/i);
var regex = /xyz/i;
有一种情况要注意: 就是如果正则中出现了反斜杠 "\" , 在用构造函数时创建正则对象时, 要转义, 比如: re = new RegExp("\\w+") // 这里的 \ 要转义, re = /\w+/ // 这样就不需要转义;
用于模式匹配的 String 方法
String.search()
参数: 要搜索的子字符串, 或者一个正则表达式.
返回: 第一个与参数匹配的子串的起始位置, 如果找不到, 返回 - 1.
说明: 不支持全局搜索, 如果参数是字符串, 会先通过 RegExp 构造函数转换成正则表达式. 如:
- var str="i am jay";
- var res=str.search("jay");
- console.log(res); //5
- console.log(str.search("hz"); //-1
String.replace(), 个人认为是正则中最强大的 API
作用: 查找并替换字符串.
第一个参数: 字符串或正则表达式,
第二个参数: 要进行替换的字符串, 也可以是函数.
用法:
当第二个参数是字符串时, 替换文本中的 $ 字符有特殊含义:
属性 | 描述 |
$1,$2,…,$99 | 匹配第 1-99 个 分组里捕获的文本 |
$& | 匹配到的子串文本 |
$` | 匹配到的子串的左边文本 |
$' | 匹配到的子串的右边文本 |
$$ | 美元符号 |
如:
- 'abc'.replace(/b/g, "{$$$`$&$'}")
- // 结果为 "a{$abc}c", 即把 b 换成了 {
- $abc
- }
当第二个参数是函数时, 如:
- "1234 2345 3456".replace(/(\d)\d{2}(\d)/g, function (match, $1, $2, index, input) {
- console.log([match, $1, $2, index, input]);
- });
- // => ["1234", "1", "4", 0, "1234 2345 3456"]
- // => ["2345", "2", "5", 5, "1234 2345 3456"]
- // => ["3456", "3", "6", 10, "1234 2345 3456"]
- String.match()
参数: 要搜索的子字符串, 或者一个正则表达式.
返回: 一个由匹配结果组成的数组. 与是否有修饰符 g 有关
非全局检索: 如果没有找到任何匹配的文本返回 null; 否则数组的第一个元素是匹配的字符串, 剩下的是小括号中的子表达式, 即 a[n]中存放的是 $n 的内容. 非全局检索返回三个属性: length 属性; index 属性声明的是匹配文本的第一个字符的位置; input 属性则存放的是被检索的字符串 string.
全局检索: 设置标志 g 则返回所有匹配子字符串, 即不提供与子表达式相关的信息. 没有 index 属性或 input 属性.
如:
- var string = "2017.06.27";
- var regex1 = /\b(\d+)\b/;
- var regex2 = /\b(\d+)\b/g;
- console.log( string.match(regex1) );
- console.log( string.match(regex2) );
- // => ["2017", "2017", index: 0, input: "2017.06.27"]
- // => ["2017", "06", "27"]
String.split(), 个人经常用到的一个 API, 简单实用
作用: 把一个字符串分割成字符串数组, 改变原字符串, 与数组方法 join 对应
参数: 正则表达式或字符串, 可以有第二个参数, 表示结果数组的最大长度 , 并且当正则使用分隔符时结果数组中是包含分隔符的.
返回: 子串组成的数组.
RegExp 的方法
RegExpObject.exec(), 比 match 强大
参数: 字符串.
返回:
非全局检索: 与 String.macth()非全局检索相同, 返回一个数组或 null.
全局检索: 尽管是全局匹配的正则表达式, 但是 exec 方法只对指定的字符串进行一次匹配. 但是可以反复调用来实现全局检索. 在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串; 匹配后, 将更新 lastIndex 为匹配文本的最后一个字符的下一个位置; 再也找不到匹配的文本时, 将返回 null, 并把 lastIndex 属性重置为 0.
- var string = "2017.06.27";
- var regex2 = /\b(\d+)\b/g;
- var result;
- while ( result = regex2.exec(string) ) {
- console.log( result, regex2.lastIndex );
- }
- // => ["2017", "2017", index: 0, input: "2017.06.27"] 4
- // => ["06", "06", index: 5, input: "2017.06.27"] 7
- // => ["27", "27", index: 8, input: "2017.06.27"] 10
RegExpObject.test(), 匹配字串
参数: 字符串.
返回: true 或 false.
RegExpObject.toString()
返回: 字符串
这两个较简单, 就不多讲了.
字符
| 指示在两个或多个项之间进行选择. 类似 JS 中的或, 又称分支条件.
/ 正则表达式模式的开始或结尾.
\ 反斜杠字符, 用来转义.
- 连字符 当且仅当在字符组 [] 的内部表示一个范围, 比如 [A-Z] 就是表示范围从 A 到 Z; 如果需要在字符组里面表示普通字符 -, 放在字符组的开头或者尾部即可.
. 匹配除换行符 \n 之外的任何单个字符.
\d 等价[0-9], 匹配 0 到 9 字符.
\D 等价[^0-9], 与 \ d 相反. \s 匹配空白符. 与 \ S 相反
\w 与以下任意字符匹配: A-Z,a-z,0-9 和下划线, 等价于 [A-Za-z0-9].
\W 与 \ w 相反, 即 [^A-Za-z0-9]
限定符(量词字符)
显示限定符位于大括号 {} 中, 并包含指示出现次数上下限的数值;*+? 这三个字符属于单字符限定符:
{n} 正好匹配 n 次.
{n,} 至少匹配 n 次.
{n,m} 匹配至少 n 次, 至多 m 次.
* 等价{0,}
+ 等价{1,}
? 等价{0,1}
注意:
显示限定符中, 逗号和数字之间不能有空格, 否则返回 null!
贪婪量词 * 和 +:JavaScript 默认是贪婪匹配, 也就是说匹配重复字符是尽可能多地匹配.
惰性 (最少重复匹配) 量词?: 当进行非贪婪匹配, 只需要在待匹配的字符后面跟随一个? 即可. 如:
- var reg = /a+/;
- var reg2 = /a+?/;
- var str = 'aaab';
- str.match(reg); // ["aaa"]
- str.match(reg2); // ["a"]
定位点(锚字符, 边界)
^ 匹配开始的位置. 将 ^ 用作括号 [] 表达式中的第一个字符, 则会对字符集求反.
$ 匹配结尾的位置.
\b 与一个字边界匹配, 如 er\b 与 "never" 中的 "er" 匹配, 但与 "verb" 中的 "er" 不匹配.
\B 非边界字匹配.
标记
中括号[] 字符组; 标记括号表达式的开始和结尾.
[...] 匹配方括号内任意字符. 很多字符在 [] 都会失去本来的意义:[^...]匹配不在方括号内的任意字符;[?.]匹配普通的问号和点号.
注意: 反斜杠字符 \ 在 [] 中仍为转义字符. 若要匹配反斜杠字符, 请使用两个反斜杠 \\.
另外不要滥用字符组这个失去意义的特性, 比如不要使用 [.] 来代替 \: 转义点号, 因为需要付出处理字符组的代价.
大括号{} 标记限定符表达式的开始和结尾.
小括号() 标记子表达式的开始和结尾, 主要作用是分组, 对内容进行区分.
(模式) 可以记住和这个模式匹配的匹配项 (捕获分组). 不要滥用括号, 如果不需要保存子表达式, 可使用非捕获型括号(?:) 来进行性能优化.
(?: 模式) 与模式 匹配, 但不保存匹配项(非捕获分组).
(?= 模式) 零宽正向先行断言, 要求匹配与模式 匹配的搜索字符串. 找到一个匹配项后, 将在匹配文本之前开始搜索下一个匹配项; 但不会保存匹配项.
(?! 模式) 零宽负向先行断言, 要求匹配与模式 不匹配的搜索字符串. 找到一个匹配项后, 将在匹配文本之前开始搜索下一个匹配项; 但不会保存匹配项.
可能会有点难懂, 不过没关系, 来几个例子就知道啥意思了
如下为捕获和非捕获分组区别:
- '13588884444'.replace(/(\d{
- 3
- })(\d{
- 4
- })(\d{
- 4
- })/g, '$1****$3')
- //=> "135****4444"
- '13588884444'.replace(/(\d{
- 3
- })(?:\d{
- 4
- })(\d{
- 4
- })/g, '$1****$2')
- //=> "135****4444"
先行断言(?= 模式):x 只有在 y 前面才匹配, 必须写成 / x(?=y)/. 解释: 找一个 x, 那个 x 的后面有 y.
先行否定断言(?! 模式): x 只有不在 y 前面才匹配, 必须写成 / x(?!y)/. 解释: 找一个 x, 那个 x 的后面没有 y.
如: 对其后紧跟 "all" 的 "is" 进行全局搜索:
- var str="Is this all there is";
- var patern=/is(?= all)/g;
- console.log(str.match(pattern)); //["is"]
- var s = "i am jay";
- var p = /j(?!ay)/g;
- s.match(p)
- //null
反向引用: 主要作用是给分组加上标识符 \ n.
\n 表示引用字符, 与第 n 个子表达式第一次匹配的字符相匹配.
反向引用的例子, 如要写一个正则支持匹配如下三种格式:
- 2016-06-12
- 2016/06/12
- 2016.06.12
最先可能想到的正则是:
var regex = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/;
其中 / 和 . 需要转义. 虽然匹配了要求的情况, 但也匹配 "2016-06/12" 这样的数据.
假设我们想要求分割符前后一致怎么办? 此时需要使用反向引用:
- var regex = /\d{
- 4
- }(-|\/|\.)\d{
- 2
- }\1\d{
- 2
- }/;
- var string1 = "2017-06-12";
- var string2 = "2017/06/12";
- var string3 = "2017.06.12";
- var string4 = "2016-06/12";
- console.log( regex.test(string1) ); // true
- console.log( regex.test(string2) ); // true
- console.log( regex.test(string3) ); // true
- console.log( regex.test(string4) ); // false
注意里面的 \1, 表示的引用之前的那个分组 (-|\/|\.). 不管它匹配到什么(比如 -),\1 都匹配那个同样的具体某个字符.
我们知道了 \1 的含义后, 那么 \2 和 \3 的概念也就理解了, 即分别指代第二个和第三个分组.
优先级顺序
\ 转义符
(), (?:), (?=), [] 括号和中括号
*,+,?,{n},{n,},{n,m}
限定符
任何元字符 ^,$,\ 定位点和序列
| 替换
实践
看完介绍内容后可以看看以下的例子, 欢迎大佬们在评论区给出答案指定!!!
匹配 16 进制颜色值
要求匹配:
- #ffbbad
- #Fc01DF
- #FFF
- #ffE
2. 匹配时间
以 24 小时制为例.
要求匹配:
23:59
02:07
3. 匹配日期
比如 yyyy-mm-dd 格式为例.
要求匹配:
2017-06-10
4. 匹配 id
要求从
<div id="container" class="main"></div>
提取出 id="container".
5. 数字的千位分隔符表示法
比如把 "12345678", 变成 "12,345,678".
可见是需要把相应的位置替换成 ",".
6. 字符串 trim 方法模拟
trim 方法是去掉字符串的开头和结尾的空白符.
7. 匹配成对标签
要求匹配:
- <title>
- regular expression
- </title>
- <p>
- laoyao bye bye
- </p>
不匹配:
<title>wrong!</p>
8. 将形如 "a=1&b=2&a=3&b=4" 的字符串压缩为 "a=1,3&b=2,4" ,(用 replace)
9.test 整体匹配某个字符串
10.IPV4 地址(优先级知识点)
欢迎大佬们在评论区给出答案指定!!!, 如想知道解析的也可在评论区提出.
来源: https://juejin.im/post/5c31a330e51d45522d17260b