提到正则,可能不少人会和我之前同样,第一时间会感到很头疼,此篇文章的目的不在于让你们变成正则高手,仅仅只是叙述一些简单正则的写法
和如何写一些简单正则
,一块儿加油吧!html
首先放出写正则的经常使用API表,毕竟做为一个api工程师,看api很重要!正则表达式
API表看完,咱们正则就学会了一半了!api
正则的精确匹配意义不大,大部分是模糊匹配,其中有两种方式:横向和纵向匹配
1.横向匹配学习
// 表示匹配:第一个字符是 "a" // 接下来是 2 到 5 个字符 "b", // 最后是字符 "c"。 const r = /ab{2,5}c/
2.纵向匹配spa
// 此时能够匹配'a1b'或者'a2b'或者'a3b' const r = /a[123]b/
既然学了,那么确定是为了能用到,那么此时咱们能够作哪些事情?那咱们能够作太多事了,基本上掌握了字符组和量词就能够应付大部分的简单正则了。code
咱们使用反向学习法,先看题分析,带着疑问去看api表,能够读懂正则以后再加上练习就等于掌握htm
Q1:图片
const r = /\d{m,n}/
解析:首先咱们看\d
,意思表明匹配数字,{m,n}
是量词,表明的是匹配次数。那么此题的意思就是匹配m到n个数字
ip
Q2:rem
const r = /[A-Za-z0-9]+/
解析:[A-Za-z0-9]
表明匹配英文字母和数字,+
表明1次及以上,此题的意思就是:匹配1次及以上的字母或数字
Q3: 匹配16进制颜色
const regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
解析:16进制可能会是6位#FFFFFF
也多是3位 #FFF
,这边才有纵向匹配,使用量词{6}
和{3}
加上管道符便可。图片解析以下:
在ES5中,共有 6 个锚:^、$、\b、\B、(?=p)、(?!p)
,经常使用的有以下2个:
^
(脱字符)匹配开头,在多行匹配中匹配行开头。$
(美圆符号)匹配结尾,在多行匹配中匹配行结尾。作题环节:
Q1:
var result = "hello".replace(/^|$/g, '#'); console.log(result); // => "#hello#"
Q2:不匹配任何字段
const r = /.^/
解析:由于此正则要求只有一个字符,但该字符后面是开头,而这样的字符串是不存在的。
\b
是单词边界,具体就是 \w
与 \W
之间的位置,也包括 \w
与 ^
之间的位置,和 \w
与 $
之间的位置。
var result = "[JS] Lesson_01.mp4".replace(/\b/g, '#'); console.log(result); // => "[#JS#] #Lesson_01#.#mp4#"
解析:\w
是字符组 [0-9a-zA-Z_] 的简写形式,而 \W
是排除字符组 1 的简写形式。
"[" 与 "J",是 \W 与 \w 之间的位置
。"S" 与 "]",也就是 \w 与 \W 之间的位置
。\b
的概念理解了,\B
的概念也就很好理解了,\B
就是 \b
的反面的意思,
var result = "[JS] Lesson_01.mp4".replace(/\B/g, '#'); console.log(result); // => "#[J#S]# L#e#s#s#o#n#_#0#1.m#p#4"
(?=p)
,其中 p 是一个子模式,即 p 前面的位置,或者说,该位置后面的字符要匹配 p。
好比 (?=l)
,表示 "l" 字符前面的位置:
var result = "hello".replace(/(?=l)/g, '#'); console.log(result); // => "he#l#lo"
而 (?!p) 就是 (?=p) 的反面意思:
var result = "hello".replace(/(?!l)/g, '#'); console.log(result); // => "#h#ell#o#"
作题环节:
Q3:数字的千分位表示
var result = "12345678".replace(/(?=(\d{3})+$)/g, ',') console.log(result); // => "12,345,678"
解析:其中(?=(\d{3})
表明匹配位置在3位数字的前面+$
表明最少出现一次。g
全局匹配
乍一看,咱们这个正则是写完了,其实否则,写完正则要多测几组,就会发现问题
var result = "123456789".replace(/(?=(\d{3})+$)/g, ',') console.log(result); // => ",123,456,789"
这是由于咱们的正则从结尾向前数,一可是 3 的倍数,就把其前面的位置替换成逗号。这个解决方法其实很简单,咱们只要不匹配开头不就行了,匹配开头咱们知道用^
,那不匹配呢?用(?!^)
正则修改以下:
var regex = /(?!^)(?=(\d{3})+$)/g; var result = "12345678".replace(regex, ',') console.log(result); // => "12,345,678" result = "123456789".replace(regex, ','); console.log(result); // => "123,456,789"
加大难度
Q4:密码长度 6-12 位,由数字、小写字符和大写字母组成,但必须至少包括 2 种字符。
不考虑“但必须至少包括 2 种字符”这一条件。咱们能够容易写出:
var regex = /^[0-9A-Za-z]{6,12}$/;
若是必需要包含数字呢:
var regex = /(?=.*[0-9])^[0-9A-Za-z]{6,12}$/;
咱们只需明白(?=.*[0-9])^
,分开来看就是 (?=.*[0-9])
和 ^
。表示开头前面还有个位置(固然也是开头,即同一个位置)。(?=.*[0-9])
表示该位置后面的字符匹配 .*[0-9]
,即,有任何多个任意字符,后面再跟个数字。就是接下来的字符,必须包含个数字。
最终答案:
// 解法1: var regex = /((?=.*[0-9])(?=.*[a-z])|(?=.*[0-9])(?=.*[A-Z])|(?=.*[a-z])(?=.*[A-Z]))^[0-9A-Za-z]{6,12}$/; // 解法2: var regex = /(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[0-9A-Za-z]{6,12}$/;
你们能够好好读一下,思考两种解法的意思。
简单点说分组就是括号
直接作题
Q1:把 yyyy-mm-dd 格式,替换成 mm/dd/yyyy
var regex = /(\d{4})-(\d{2})-(\d{2})/; var string = "2017-06-12"; var result = string.replace(regex, "$2/$3/$1"); console.log(result); // => "06/12/2017"
解析:其中 replace 中的,第二个参数里用 $1
、$2
、$3
指代相应的分组。
Q2:一个正则支持匹配以下三种格式:`2016-06-12
2016/06/12
2016.06.12`
很容易有以下答案
var regex = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\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) ); // true
其中 /
和 .
须要转义。虽然匹配了要求的状况,但也匹配 "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
都匹配那个一样的具体某个字符。
括号嵌套
以左括号(开括号)为准
var regex = /^((\d)(\d(\d)))\1\2\3\4$/; var string = "1231231233"; console.log( regex.test(string) ); // true console.log( RegExp.$1 ); // 123 console.log( RegExp.$2 ); // 1 console.log( RegExp.$3 ); // 23 console.log( RegExp.$4 ); // 3
可视化形式以下:
Q3:字符串 trim 方法模拟。
trim 方法是去掉字符串的开头和结尾的空白符
// 解法1:匹配到开头和结尾的空白符,而后替换成空字符 function trim(str) { return str.replace(/^\s+|\s+$/g, ''); } console.log( trim(" foobar ") ); // => "foobar // 解法2:匹配整个字符串,而后用引用来提取出相应的数据 function trim (str) { return str.replace(/^\s*(.*?)\s*$/g, "$1"); } console.log( trim(" foobar ") ); // => "foobar"
Q4:将每一个单词的首字母转换为大写
function titleize (str) { return str.toLowerCase().replace(/(?:^|\s)\w/g, function (c) { return c.toUpperCase(); }); } console.log( titleize('my name is epeli') ); // => "My Name Is Epeli"
Q5: HTML 转义和反转义
// 将HTML特殊字符转换成等值的实体 function escapeHTML (str) { var escapeChars = { '<' : 'lt', '>' : 'gt', '"' : 'quot', '&' : 'amp', '\'' : '#39' }; return str.replace(new RegExp('[' + Object.keys(escapeChars).join('') +']', 'g'), function (match) { return '&' + escapeChars[match] + ';'; }); } console.log( escapeHTML('<div>Blah blah blah</div>') ); // => "<div>Blah blah blah</div>"; // 实体字符转换为等值的HTML。 function unescapeHTML (str) { var htmlEntities = { nbsp: ' ', lt: '<', gt: '>', quot: '"', amp: '&', apos: '\'' }; return str.replace(/\&([^;]+);/g, function (match, key) { if (key in htmlEntities) { return htmlEntities[key]; } return match; }); } console.log( unescapeHTML('<div>Blah blah blah</div>') ); // => "<div>Blah blah blah</div>"
其实到这里,基本上经常使用的正则api都已经出现了,剩下的就是活学活用了,你们能够在工做中某些之前用js的api的地方如今换成正则,即装b,又能够更好的掌握正则。
因为本人技术有限,如文内有错误,还望指出,感谢!
参考文章:《JavaScript正则表达式迷你书》