前言:
实际上对于正则表达式而言,绝大多数的前端工程师都不陌生,但也并不熟悉。我为什么这么说呢?因为在实际开发过程中,为了开发进度,很少有人去思考这个正则表达式该怎么写,而是直接百度。而对于一些常见的正则表达式可能都需要百度之后试很久才能找到一个真正可用的,这样实际上也是比较浪费时间的。此文会抱着学习的态度去进一步探究正则表达式的奥义,就不要说一些百度上面有的话了。如果总结有任何疏漏以及错误还请各位大佬多多指教,作为萌新的我在这里先谢过了!如果在此文中略有收获不仿给作者点个赞以示鼓励吧,在这里先谢谢诸位了!
正则表达式的定义:
使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。
正则表达式的用途:
它的主要用途有三个:1.查找特定字符-文本搜索;2.替换文本-敏感词过滤;3.数据有效性校验-表单验证。
正则表达式的创建方法:
- 字面量:
var RE = /text/igm;
- 构造函数:
var RE = new RegExp('text', 'igm');
注:img是修饰符,什么是修饰符呢?请看后续的解释。
修饰符:
- i全称ignoreCase,执行对大小写不敏感的匹配。
var RE = new RegExp('text', 'i');
var str = 'TEXT';
console.log(RE.test(str));//true
注:test()字符串中有则返回true,无则返回false。
- g全称global,执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
var RE = new RegExp('js','g');
var str = '我爱js,/njs123';
console.log(str.match(RE));// ["js", "js"]
注:match()以数组的形式返回匹配到的结果,全局匹配返回所有匹配到的值
- m全称multiline,执行多行匹配。
var RE = /html/m;
var str = '1.html\n2.htmls\n3.htmlcssjs';
console.log(str.match(RE));
//["html", index: 2, input: "1.html↵2.htmls↵3.htmlcssjs", groups: undefined]
注:match()以数组的形式返回匹配到的结果,换行匹配只会匹配第一个匹配到的值及位置,除非和全局匹配结合使用。
正则的实例属性:
前言:在MDN中有许多方法以及属性是非标准的,还有一些是草案,对于这些非标准的属性及方法我不会过多的提及。
- global:global 属性表明正则表达式是否使用了 "g" 标志。该属性只读。
var RE = /t/g;
console.log(RE.global);//true;
- ignoreCase 属性表明正则表达式是否使用了 "i" 标志。该属性只读。
var RE = /t/i;
console.log(RE.ignoreCase);//true;
- multiline 属性表明正则表达式是否使用了 "m" 标志。该属性只读。
var RE = /t/m;
console.log(RE.multiline);//true;
- source 属性返回一个值为当前正则表达式对象的模式文本的字符串,该字符串不会包含正则字面量两边的斜杠以及任何的标志字符。
var RE = /t/img;
console.log(RE.source);//t
- unicode属性表明正则表达式带有"u" 标志。该属性只读。
var regex = new RegExp('\u{61}', 'u');
console.log(regex.unicode); // true
- lastIndex 是正则表达式的一个可读可写的整型属性,用来指定下一次匹配的起始索引。
var RE = new RegExp('text', 'iy');
var str = 'TEXTtext';
RE.lastIndex = 4;
console.log(RE.test(str));//true
正则的实例方法:
- exec() 方法在一个指定字符串中执行一个搜索匹配。
var RE = /t/ig;
var str = 'TEXT';
console.log(RE.exec(str));//["T", index: 0, input: "TEXT", groups: undefined]
console.log(RE.exec(str));//["T", index: 3, input: "TEXT", groups: undefined]
console.log(RE.exec(str));//null
注:无论是否全局匹配,都会返回分组中匹配到的内容;无论是否全局匹配都只返回当前匹配到的内容,而不是所有,只不过全局匹配时可以继续匹配下去。
- test()方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。
var RE = /t/i;
var str = 'Text';
console.log(RE.test(str));//true
- toString() 返回一个表示该正则表达式的字符串。
var RE = /t/i;
console.log(RE.toString());//'/t/i'
正则的构造函数属性:
- input 匹配的字符串:
var RE = /T/ig;
var str = 'text title';
RE.exec(str);
console.log(RegExp.input);//text title
- lastMatch 最近一次的匹配项:
var RE = /T/ig;
var str = 'text';
RE.exec(str);
console.log(RegExp.lastMatch);//t
- leftContext字符串中匹配到的内容之前的文本
var RE = /T/ig;
var str = '1text';
RE.exec(str);
console.log(RegExp.leftContext);//1
- rightContext 字符串中匹配到的内容之后的文本
var RE = /T/ig;
var str = '1text';
RE.exec(str);
console.log(RegExp.rightContext);//ext
- lastParen 最近一次匹配的捕获组
var RE = /(T)e/ig;
var str = '1text';
RE.exec(str);
console.log(RegExp.lastParen);//t
注:这些属性不是特别常用,而且各个浏览器兼容性不一样
String对象和正则表达式相关的方法:
- search()方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置。
var RE = /t/;
var str = 'Text';
console.log(str.search(RE));//3
- match()只有非全局匹配,才会返回分组中匹配到的内容,全局匹配只会一次返回所有匹配到的字符。
var RE = /(t)e/i;
var str = 'Text';
console.log(str.match(RE));// ["Te", "T", index: 0, input: "Text", groups: undefined]
var RE = /(t)e/gi;
var str = 'Text';
console.log(str.match(RE));//["Te"]
- split()把字符串分割为字符串数组。
var RE = /e/;
var str = 'Text';
console.log(str.split(RE));//["T", "xt"]
- replace()替换与正则表达式匹配的子串:
var RE = /js/ig;
var str = 'I love js';
console.log(str.replace(RE,'you'));//I love you
元字符:
- \w查找单词字符:
var RE = /\w/g;
var str = 'I love js';
console.log(str.match(RE));//["I", "l", "o", "v", "e", "j", "s"]
- \W查找非单词字符:
var RE = /\W/g;
var str = 'I love js';
console.log(str.replace(RE,','));//I,love,js
- \d查找数字:
var RE = /\d/g;
var str = '1、2、3、4、5,我们等得好辛苦。1、2、3、4、5、6、7,我们等得好着急。';
console.log(str.match(RE));//["1", "2", "3", "4", "5", "1", "2", "3", "4", "5", "6", "7"]
- \D查找非数字字符:
var RE = /\D/g;
var str = '1、2、3、4、5,我们等得好辛苦。1、2、3、4、5、6、7,我们等得好着急。';
console.log(str.match(RE));// ["、", "、", "、", "、", ",", "我", "们", "等", "得", "好", "辛", "苦", "。", "、", "、", "、", "、", "、", "、", ",", "我", "们", "等", "得", "好", "着", "急", "。"]
- \s查找空白字符:
var RE = /\s/g;
var str = "182 2886 5237";
console.log(str.replace(RE,'-'));//182-2886-5237
- \S查找非空白字符:
var RE = /\S/g;
var str = "182 2886 5237";
console.log(str.match(RE).toString().replace(/,/g,''));//18228865237
- \b匹配单词边界(以某个单词开头):
var RE = /\bt/g;
var str = "text";
console.log(str.replace(RE,'T'));//Text
- \B匹配非单词边界(以某个单词结尾:
var RE = /\Bt/g;
var str = "text";
console.log(str.replace(RE,'T'));//texT
- \n查找换行符:
var RE = /\n/g;
var str = "text\n123";
console.log(str.replace(RE,''));//text123
- \uxxxx查找以十六进制数 xxxx 规定的 Unicode 字符:
var RE = /[\u4e00-\u9fa5]/g;//该正则用于匹配中文
var str = "我爱你js";
console.log(str.match(RE).toString().replace(/,/g,''));//我爱你
- .查找单个字符,除了换行和行结束符:
var str = "abcd";
var RE = /.+/g;
console.log(RE.exec(str));
方括号:
- [abc]查找方括号之间的任何字符:
var RE = /[js]/i;//匹配j或者s,全局匹配会将两个字符都匹配
var str = "JavaScript";
str.match(RE);
console.log(RegExp.lastMatch);//J
- [^abc]查找非方括号之间的任何字符:
var RE = /[^js]/ig;//匹配j和s之外的任意字符
var str = "JavaScript";
console.log(str.match(RE));//["a", "v", "a", "c", "r", "i", "p", "t"]
- [0-9]查找任何从 0 至 9 的数字:
var RE = /[0-9]/g;//匹配0到9的任意字符
var str = "c++20";
console.log(str.match(RE));//["2", "0"]
- [a-z]查找任何从小写 a 到小写 z 的字符:
var RE = /[a-z]/g;//小写字母
var str = "JavaScript";
console.log(str.match(RE));//["a", "v", "a", "c", "r", "i", "p", "t"]
- [A-Z]查找任何从大写 A 到大写 Z 的字符:
var RE = /[A-Z]/g;//大写字母
var str = "JavaScript";
console.log(str.match(RE));//["J", "S"]
- [A-z]查找任何从大写 A 到小写 z 的字符:
var RE = /[A-z]/g;
var str = "JavaScript";
console.log(str.match(RE));//["J", "a", "v", "a", "S", "c", "r", "i", "p", "t"]
- [adgk]查找给定集合内的任何字符:
var RE = /[adgk]/g;
var str = "JavaScript我";
console.log(str.match(RE));//["a", "a"]
- [^adgk]查找给定集合外的任何字符:
var RE = /[^adgk]/g;
var str = "JavaScript我";
console.log(str.match(RE));//["J", "v", "S", "c", "r", "i", "p", "t", "我"]
量词:
- n+匹配任何包含至少一个 n 的字符串:
var RE = /t+/g;//{1,}
var str = "text";
console.log(str.match(RE));//["t", "t"]
- n*匹配任何包含零个或多个 n 的字符串:
var RE = /t*/g;//{0,}
var str = "text";
console.log(str.match(RE));//["t", "", "", "t", ""]
- n?匹配任何包含零个或一个 n 的字符串:
var RE = /t?/g;//{0,1}
var str = "text";
console.log(str.search(RE));//0
- n{x}匹配包含 X 个 n 的序列的字符串:
var RE = /t{1}/;
var str = "text";
console.log(str.match(RE));//["t", index: 0, input: "text", groups: undefined]
- n{x,}X 是一个正整数。前面的模式 n 连续出现至少 X 次时匹配:
var RE = /t{1,}/g;
var str = "text";
console.log(str.match(RE));//["t", "t"]
- n{x,y}X 和 Y 为正整数。前面的模式 n 连续出现至少 X 次,至多 Y 次时匹配:
var RE = /t{1,2}/g;
var str = "text";
console.log(str.match(RE));//["t", "t"]
- n$匹配任何结尾为 n 的字符串:
var RE = /t$/g;
var str = "text";
console.log(str.match(RE));//["t"]
- ^n匹配任何开头为 n 的字符串:
var RE = /^J/ig;
var str = "javascript";
console.log(str.match(RE));//["j"]
- ?=n匹配任何其后紧接指定字符串 n 的字符串(前瞻性匹配):
var RE = /J(?=a)/ig;//如果j后面紧跟a则匹配,否则不匹配
var str = "javascript";
console.log(str.match(RE));//["j"]
- ?!n匹配任何其后没有紧接指定字符串 n 的字符串(负向前瞻性匹配):
var RE = /J(?!v)/ig;//如果j后面紧跟的不是v则匹配,否则不匹配
var str = "javascript";
console.log(str.match(RE));//["j"]
贪婪匹配与非贪婪匹配:
- 贪婪匹配:
贪婪匹配只与量词有关,正则默认情况下有量词的匹配都是贪婪的!
var str = "aaabbb";
var RE = /a+/;//+为匹配一次或更多,它会直接按最多的进行匹配;
str.match(RE);
console.log(RegExp.lastMatch);//aaa
- 非贪婪匹配:
非贪婪匹配就是条件允许的情况下按最少的次数进行匹配,转换也简单,在量词后面加个?就行了!
var str = "aaabbb";
var RE = /a+?/;//+为匹配一次或更多,它会直接按最多的进行匹配;
str.match(RE);
console.log(RegExp.lastMatch);//a
注:正则匹配的是第一个可能匹配的,而不是最合适的匹配
var str = "aaab";
var RE = /a+?b/;//?是尽可能的少而不是绝对的最少,如果你需要绝对的最少需要写死
str.match(RE);
console.log(RegExp.lastMatch);//aaab
选择、分组和引用:
- 选择:
var str = "htmljs";
var RE = /html|css|js/;//三选一,从左到右匹配返回第一个匹配到的结果
str.match(RE);
console.log(RegExp.lastMatch);//html
- 分组:
(1). 普通分组:
var str = "abab";
var RE = /(ab)+/;
str.match(RE);
console.log(RegExp.lastMatch);//abab
(2). 捕获分组:
var str = "abcd";
var RE = /(ab)c/g;
console.log(RE.exec(str));//["abc", "ab", index: 0, input: "abcd", groups: undefined]
(3)非捕获分组:
var str = "abcd";
var RE = /(?:ab)c/g;
console.log(RE.exec(str));//["abc", index: 0, input: "abcd", groups: undefined]
- 引用:
引用是对分组的引用:
var str = "ab c ab";
var RE = /(ab) c \1/g;
console.log(str.match(RE));//["ab c ab"]
常用正则表达式查询表:
1、"^\w+$" //由数字、26 个英文字母或者下划线组成的字符串
2、"^1\d{10,}$" //手机号码
3、"^[1-9]{1}[0-9]{14}$|^[1-9]{1}[0-9]{16}([0-9]|[xX])$" //身份证号
4、"[1-9]\d{5}(?!\d)" //匹配中国邮政编码
5、"^[\u4e00-\u9fa5]{2,4}$" //中文名字,2-4 个字
6、"[\u4e00-\u9fa5]"匹配中文
思考:
如何去除空格和换行符:
var str = '123456-789 \n78989';
console.log(str.replace(/\s/mg,""));//123456-78978989
如何去除数字以外的其他字符:
var str = '123456-789 \n78989';
console.log(str.replace(/\D/mg,""));//12345678978989
如何检测字符串是否为IP:
var RE = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/g;
var str = "168.1.3.565";
console.log(RE.test(str));//true
QQ号、昵称和密码:
//QQ号规则:(1)、全是数字;(2)、首尾不能为0;(3)、最少5位;(4)、目前最多11位
var QQ = /^[1-9]\d{4,}$/g;
var str = '456456456';
console.log(str.match(QQ));//["456456456"]
//昵称:(1)、2-18位;(2)、中英文;(3)、数字;(4)下划线;
var Nickname = /^[\w\u4e00-\u9fa5]{2,18}$/g;
var str = '45456你妈的_fjakfj';
console.log(str.match(Nickname));//["45456你妈的_fjakfj"]
//密码:(1)、6-16位;(2)、区分大小写;(3)、不能用空白字符:
var Nickname = /^\S{6,16}$/g;
var str = '45456@!';
console.log(str.match(Nickname));//["45456你妈的_fjakfj"]
去除字符串首尾的空白字符:
var str = ' \n123456-78978989 \n';
console.log(str.replace(/^\s+$/mg,""));//123456-78978989
转驼峰:
var str = "background-color";
var RE = /-([a-z])/ig;
console.log(str.replace(RE,function(all,letter){
return letter.toUpperCase();
}))//backgroundColor
email邮箱验证:
var email = "9978874@163.com";
var RE = /^\w+\@[0-9A-z]+\.[0-9A-z]+$/;
console.log(RE.test(email));//true
url:
var url = "https://juejin.im/editor/drafts/5e5ef3c8518825492b50b7ef";
var RE = /^(http:\/\/|https:\/\/)?([^:\/]+)(:\d+)?(\/.*)?$/g;
console.log(url.match(RE));//["https://juejin.im/editor/drafts/5e5ef3c8518825492b50b7ef"]
文本搜索:
var RE = /[\u4e00-\u9fa5]/g;//该正则用于匹配中文
var str = "我爱你js";
console.log(str.search(RE));//0
匹配金额:
var str = "肯德基¥15.5元";
var RE = /\d+\.?\d{2}/;
str.match(RE);
console.log(RegExp.lastMatch);//15.5
敏感词过滤:
var str = "草尼玛,杂碎!";
var RE = /[草尼玛杂碎]/g;
console.log(str.replace(RE,"*"));// ***,**!
表单验证:
1、用户名:/^[\w\u4e00-\u9fa5]{2,18}$/g//(1)、2-18位;(2)、中英文;(3)、数字;(4)下划线;
2、密码:"^\w+$" //由数字、26 个英文字母或者下划线组成的字符串
3、邮箱:/^\w+\@[0-9A-z]+\.[0-9A-z]+$//匹配的不光qq邮箱
4、手机号:"/^1\d{10,}$/" //手机号码
匹配标签中的HTML内容:
var str = "aldfk<p><a>这是一段HTML代码</a></p>afadsf";
var RE = /<([A-z]+)>.*<\/\1>/;
console.log(str.match(RE));
// ["<p><a>这是一段HTML代码</a></p>", "p", index: 0, input: "<p><a>这是一段HTML代码</a></p>", groups: undefined]
匹配手机号:
let RE = /^1\d{10,}$/;
let str = '18245564455';
console.log(RE.test(str));
匹配文件类型(如果要匹配其他的文件,只需要改成其对应的后缀名即可)
let RE = /(.jpg|.png|.jpeg|.gif)$/;//匹配图片
let str = '1.jpg';
console.log(RE.test(str)); //true
参考文献:
- MDN RegExp
- javascript高级程序设计(第三版)——尼古拉斯.泽卡斯;
- 菜鸟教程 RegExp 对象
后记:
兄弟,别白嫖了,点个赞。谢谢!动动手指,反正又不要钱,你说是不是呢? 还有我提醒各位一句:百度来的始终都是知其然,不知其所以然。如果百度不到你想要的正则,难道要靠猜吗?(比如说那个QQ号、昵称和密码的正则)所以纸上得来终觉浅,绝知此事要躬行!另外提醒一句:正则都是操作字符串的!