关于javascript:迅速掌握正则表达式

6次阅读

共计 5282 个字符,预计需要花费 14 分钟才能阅读完成。

1. 前言

提到正则,可能很多人会和我以前一样,第一工夫会感到很头疼,此篇文章的目标不在于让大家变成正则高手,仅仅只是叙述一些 简略正则的写法 如何写一些简略正则,一起加油吧!

2. 注释

2.1 福利章节

首先放出写正则的罕用 API 表,毕竟作为一个 api 工程师,看 api 很重要!

API 表看完,咱们正则就学会了一半了!

2.2 意识含糊匹配

正则的准确匹配意义不大,大部分是含糊匹配,其中有两种形式:横向和纵向匹配
1. 横向匹配

// 示意匹配:第一个字符是 "a"
// 接下来是 2 到 5 个字符 "b",// 最初是字符 "c"。const r = /ab{2,5}c/

2. 纵向匹配

// 此时能够匹配 'a1b' 或者 'a2b' 或者 'a3b'
const r = /a[123]b/

既然学了,那么必定是为了能用到,那么此时咱们能够做哪些事件?那咱们能够做太多事了,基本上把握了字符组和量词就能够应酬大部分的简略正则了。

咱们应用反向学习法,先看题剖析,带着疑难去看 api 表,能够读懂正则之后再加上练习就等于把握

Q1:

const r = /\d{m,n}/

解析:首先咱们看 \d,意思代表匹配数字,{m,n} 是量词,代表的是匹配次数。那么此题的意思就是 匹配 m 到 n 个数字

Q2:

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} 加上管道符即可。图片解析如下:

2.3 正则匹配地位

在 ES5 中,共有 6 个锚:
^、$、\b、\B、(?=p)、(?!p),罕用的有如下 2 个:

2.31 ^ 和 $

  • ^(脱字符)匹配结尾,在多行匹配中匹配行结尾。
  • $(美元符号)匹配结尾,在多行匹配中匹配行结尾。

做题环节:

Q1:

var result = "hello".replace(/^|$/g, '#');
console.log(result);
// => "#hello#"

Q2:不匹配任何字段

const r = /.^/

解析:因为此正则要求只有一个字符,但该字符前面是结尾,而这样的字符串是不存在的。

2.32 \b 和 \B

\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 的简写模式。

  • 第 1 个,两边字符是 "[" 与 "J",是 \W 与 \w 之间的地位
  • 第 2 个,两边字符是 "S" 与 "]",也就是 \w 与 \W 之间的地位
  • 第 3 个,两边字符是空格与 “L”,也就是 \W 与 \w 之间的地位。
  • 第 4 个,两边字符是 “1” 与 “.”,也就是 \w 与 \W 之间的地位。
  • 第 5 个,两边字符是 “.” 与 “m”,也就是 \W 与 \w 之间的地位。
  • 第 6 个,位于结尾,后面的字符 “4” 是 \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"

2.33 (?=p) 和 (?!p)

(?=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}$/;

大家能够好好读一下,思考两种解法的意思。

2.4 分组

简略点说分组就是括号

间接做题

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>') );
// => "&lt;div&gt;Blah blah blah&lt;/div&gt";

// 实体字符转换为等值的 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('&lt;div&gt;Blah blah blah&lt;/div&gt;') );
// => "<div>Blah blah blah</div>"

3. 结尾

其实到这里,基本上罕用的正则 api 都曾经呈现了,剩下的就是活学活用了,大家能够在工作中某些以前用 js 的 api 的中央当初换成正则,即装 b,又能够更好的把握正则。

因为自己技术无限,如文内有谬误,还望指出,感激!

参考文章:《JavaScript 正则表达式迷你书》


  1. 0-9a-zA-Z_ ↩
正文完
 0