前端进击者让前端飞

理解Javascript的正则表达式

2020-02-24  本文已影响0人  秦至

前言

本文4089字,阅读大约需要12分钟。

总括: 本文基于Javascript的正则表达式,结合笔者个人的思考来对正则表达式的特性进行讲解。

事亲以敬,美过三牲。

正文

相信很多人第一次见到正则表达式的第一印象都是懵逼的,对新手而言一个正则表达式就是一串毫无意义的字符串,让人摸不着头脑。但正则表达式是个非常有用的特性,不管是Javascript、PHP、Java还是Python都有正则表达式。俨然正则表达式已经发展成了一门小语言。作为编程语言的一部分,它不想变量,函数,对象这种概念那么容易理解。很多人对于正则表达式的理解都是基于简单的匹配,等到业务中用到完全靠从网上copy来解决问题。不得不说,随着各种开源技术社区的发展,靠copy的确能解决业务中绝大多数的问题,但作为一名有追求的程序员,是绝对不会让自己仅仅依靠Ctrl C + Ctrl V来编程的。本文基于Javascript的正则表达式,结合笔者个人的思考和社区内一些优秀正则表达式文章来对正则表达式进行讲解。

Javascrip中的正则表达式使用方法

简单介绍下,在Javascript中使用正则表达式有两种方式:

  1. 构造函数:使用内置的RegExp构造函数;
  2. 字面量:使用双斜杠(//);

使用构造函数:

var regexConst = new RegExp('abc');

使用双斜杠:

var regexLiteral = /abc/;

匹配方法

Javascript中的正则表达式对象主要有两个方法,testexec

test()方法接受一个参数,这个参数是用来与正则表达式匹配的字符串,如下例子:

var regex = /hello/;
var str = 'hello world';
var result = regex.test(str);
console.log(result);
// returns true

exec()方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null

var regex = /hello/;
var str = 'hello world';
var result = regex.exec(str);
console.log(result);
// returns [ 'hello', index: 0, input: 'hello world', groups: undefined ]
// 匹配失败会返回null
// 'hello' 待匹配的字符串
// index: 正则表达式开始匹配的位置
// input: 原始字符串

下文都用test()方法来进行测试。

标志

标志是用来表示搜索字符串范围的一个参数,主要有6个标志:

标志 描述
g 全局搜索。
i 不区分大小写搜索。
m 多行搜索。
s 允许 . 匹配换行符。
u 使用unicode码的模式进行匹配。
y 执行“粘性”搜索,匹配从目标字符串的当前位置开始,可以使用y标志。

双斜杠语法:

var re = /pattern/flags;

构造函数语法:

var re = new RegExp("pattern", "flags");

看下实例:

var reg1 = /abc/gi;
var reg2 = new RegExp("abc", "gi");
var str = 'ABC';
console.log(reg1.test(str)); // true
console.log(reg2.test(str)); // true

正则表达式的思考

正则表达式是对字符串进行匹配的一种模式。

请记住,正则表达式是对字符串的操作,所以一般具有字符串类型的编程语言都会有正则表达式。

对于字符串而言,是由两部分构成的:内容和位置

比如一个字符串:

'hello World';

它的内容就是:

'h', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'

如上字符串中每一个独立的字母就是这个字符串的内容,而位置指的是:

image

位置所指就是相邻字符之间的位置,也就是上图中箭头的位置。

匹配内容相比匹配位置来说更为复杂,先看下简单的匹配方式:

简单匹配

最简单的匹配方式就是完整的去匹配一个字符串:

 var regex = /hello/;
 console.log(regex.test('hello world'));
 // true

复杂匹配

正则表达式中有很多特殊字符用来匹配字符串,解决的就是匹配多少(按位置匹配)和匹配谁(按内容匹配)的问题。我们先来看下用来决定匹配谁的一些特殊字符:

匹配内容

简单的特殊字符

简单的匹配内容有如下的特殊字符:

上面的特殊字符都只能匹配某个目标字符串一次,但很多场景下我们需要匹配目标字符串多次,比如我们想匹配无数个a,上面的特殊字符就无法满足我们的需求了,因此匹配内容的特殊字符里还有一部分是用来解决这个问题的:

为了更为方便的使用,还提供了三个比较常用规则更为方便的写法:

使用以上内容匹配普通的字符已经可以满足需求了,但像换行符、换页符和回车等特殊的符号以上的特殊字符无法满足需求,因此正则表达式还提供了专门用来匹配特殊符号的特殊字符:

内容匹配进阶

匹配位置

再次强调,这里的位置是前面图里箭头的位置。

JS中可以使用正则表达式的方法

方法 描述
RegExp.prototype.exec 一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回 null)。
RegExp.prototype.test 一个在字符串中测试是否匹配的RegExp方法,它返回 true 或 false。
String.prototype.match 一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null。
String.prototype.matchAll 一个在字符串中执行查找所有匹配的String方法,它返回一个迭代器(iterator)。
String.prototype.search 一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1。
String.prototype.replace 一个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串。
String.prototype.split 一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 String 方法。

练习

var regex = /^\d{10}$/;
console.log(regex.test('9995484545'));
// true

分析下上面的正则:

  1. 我们匹配想要跨越整个字符串,不能字符串中有我们要匹配的内容就可以,因此使用^$限制了开头和结尾;
  2. \d用来匹配数字,它相当于[0-9];
  3. {10}匹配了\d表达式,即\d重复10次;
var regex = /^(\d{1,2}-){2}\d{2}(\d{2})?$/;
console.log(regex.test('10-01-1990'));
// true
console.log(regex.test('2-01-90'));
// true
console.log(regex.test('10-01-190'));

分析上面的正则:

  1. 同理我们使用^$限制了开头和结尾;
  2. \d{1,2},表示匹配1位或2位数字;
  3. -来匹配连字符,无特殊含义;
  4. ()包裹了一个子表达式,也叫捕获组;
  5. {2}表示匹配上面的子表达式两次;
  6. \d{2}匹配两位数字;
  7. (\d{2})?子表达式中匹配两位数字,然后匹配子表达式一次或是不匹配;
var reg = /(\B[A-Z])/g;
'oneTwoThree'.replace(reg, '_$1').toLowerCase();

分析上面的正则:

  1. \B避免将首字母大写的字符也转换掉;
  2. ([A-Z])捕获组捕获大写字母;
  3. 然后replace里使用$n这样的语法来表示前面的捕获;
  4. 调用toLowerCase转为小写字母;

结论

正则表达式各种规则很难记,希望本篇文章可以帮大家更好的去记忆这些特殊字符,也希望大家能写出牛叉的正则表达式。共勉。最后提供一个练习正则表达式的链接:https://www.hackerrank.com/domains/regex和一个工具网站:https://regex101.com/

以上。


能力有限,水平一般,欢迎勘误,不胜感激。

订阅更多文章可关注公众号「前端进阶学习」,回复「666」,获取一揽子前端技术书籍

前端进阶学习
上一篇 下一篇

猜你喜欢

热点阅读