前言:
本文介绍正则表达式入门的一些知识,用来做笔记用的,很系统~
正则表达式是匹配模式,要么匹配字符,要么匹配位置。这是正则表达式核心。
匹配字符是一个个扫描,类似于用for循环一样。 当然,你可以任意定义它的匹配方式。
注:正则是使用JavaScript写的,阅读本文需要一定的时间和耐心。
两种模糊匹配
如果正则只有精确匹配是没多大意义的,比如 /hello/,也只能匹配字符串中的 “hello” 这个子串。
var regex = /hello/; console.log( regex.test("hello") ); // => true
横向模糊匹配
横向模糊指的是,一个正则可匹配的字符串的长度不是固定的,可以是多种情况的。
其实现的方式是使用量词。譬如 {m,n},表示连续出现最少 m 次,最多 n 次。
比如正则 /ab{2,5}c/ 表示匹配这样一个字符串:第一个字符是 “a”,接下来是 2 到 5 个字符 “b”,最后 是字符 “c”。
用于横向模糊匹配的量词:
var regex = "a{1,2}b{3,}c{4}d?e+f*/"
贪婪匹配
var regex = /\d{2,5}/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) );
// => ["123", "1234", "12345", "12345"]
其中正则 /\d{2,5}/,表示数字连续出现 2 到 5 次。会匹配 2 位、3 位、4 位、5 位连续数字。
但是其是贪婪的,它会尽可能多的匹配。你能给我 6 个,我就要 5 个。你能给我 3 个,我就要 3 个。 反正只要在能力范围内,越多越好。
惰性匹配
var regex = /\d{2,5}?/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) );
// => ["12", "12", "34", "12", "34", "12", "34", "56"]
其中 /g 是全局匹配
其中 /\d{2,5}?/ 表示,虽然 2 到 5 次都行,当 2 个就够的时候,就不再往下尝试了。
var regex = /a{1,2}?b{3,}?c{4}?d??e+?f*?
纵向模糊匹配
纵向模糊指的是,一个正则匹配的字符串,具体到某一位字符时,它可以不是某个确定的字符,可以有多种 可能。
其实现的方式是使用字符组。譬如 [abc],表示该字符是可以字符 “a”、“b”、“c” 中的任何一个。
比如 /a[123]b/ 可以匹配如下三种字符串: “a1b”、“a2b”、“a3b”。
字符组
需要注意的是,字符组是匹配“组”中的一个字符
例如:[abc],表示匹配一个字符,它可以是"a",“b”,"c"之一。
连字符
如果字符的可能性非常多的情况下,可以使用范围表示法。【字符组的简写形式】
例如:[123456abcdefGHIJKLM],可以写成[1-6a-fG-M]。用连字符 - 来省略和简写。
注意:
因为连字符有特殊用途,那么要匹配 “a”、"-"、“z” 这三者中任意一个字符,该怎么做呢?
不能写成 [a-z],因为其表示小写字符中的任何一个字符。
可以写成如下的方式:[-az] 或 [az-] 或 [a-z]。
即要么放在开头,要么放在结尾,要么转义。总之不会让引擎认为是范围表示法就行了。
排除字符
纵向模糊匹配,还有一种情形就是,某位字符可以是任何东西,但就不能是 “a”、“b”、“c”。
此时就是排除字符组(反义字符组)的概念。例如 [^abc],表示是一个除 “a”、“b”、"c"之外的任意一个字 符。字符组的第一位放 ^(脱字符),表示求反的概念。
当然,也有相应的范围表示法。
常见的简写形式
如果要匹配任意字符怎么办?可以使用 [\d\D]、[\w\W]、[\s\S] 和 [^] 中任何的一个。
多选分支
一个模式可以实现横向和纵向模糊匹配。而多选分支可以支持多个子模式任选其一。
具体形式如下:(p1|p2|p3),其中 p1、p2 和 p3 是子模式,用 |(管道符)分隔,表示其中任何之一。
例如要匹配字符串 “good” 和 “nice” 可以使用 /good|nice/。
var regex = /good|nice/g;
var string = "good idea, nice try.";
console.log( string.match(regex) );
// => ["good", "nice"]
而把正则改成 /goodbye|good/,结果是:
var regex = /goodbye|good/g;
var string = "goodbye";
console.log( string.match(regex) );
// => ["goodbye"]
也就是说,分支结构也是惰性的,即当前面的匹配上了,后面的就不再尝试了。
总结
下面举两个小案例
匹配字符,无非就是字符组、量词和分支结构的组合使用罢了。(正则并不是只有唯一写法)
要求匹配:
#ffbbad
#Fc01DF
#FFF
#ffE
分析:
表示一个 16 进制字符,可以用字符组 [0-9a-fA-F]。
其中字符可以出现 3 或 6 次,需要是用量词和分支结构。
使用分支结构时,需要注意顺序。
正则如下:
var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
var string = "#ffbbad #Fc01DF #FFF #ffE";
console.log( string.match(regex) );
// => ["#ffbbad", "#Fc01DF", "#FFF", "#ffE"]
其可视化形式:
需求2:使用过mavonEditor的应该遇到过的一个需求,它是一个前端markdown插件,可以将文字图片转化为html字符串存入后端,但是取出来的时候正常显示到markdown的编辑页面,有些困难。
我做过的尝试:将markdown转的html字符串和正常编辑时的字符串在数据库中存两份,前端显示取一份,编辑的时候使用另一份。功能是实现了,就是有点占内存。于是,我尝试使用正则表达式将两份字符串进行转化:
类比案例如下:保留html中的标签就,将其他标签中的文字提取出来:
var html = "<div>" +
"<p>你好呀</p>" +
"<p>nifdkslafjkdlsa</p>" +
"<img src='图片地址1' alt=''>" +
"<p>1223323333</p>" +
"<img src='图片地址2'>" +
"</div>";
/ 替换
var output = html.replace(/<(?!\/?br\/?.+?>|\/?img.+?>)[^<>]*>/gi, "");
console.log(output);//你好呀nifdkslafjkdlsa<img src='图片地址1' alt=''>1223323333<img src='图片地址2'>
这个正则借鉴于: 传送门
本文摘自“老姚正则表达式迷你书”