关于前端:一文让你彻底搞懂正则表达式从此不再copy

0次阅读

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

正则表达式是来匹配一个字符串的。”Regular Expression” 这个词太长了,咱们通常应用它的缩写 “regex” 或者 “regexp”。正则表达式能够被用来替换字符串中的文本、验证表单、基于模式匹配从一个字符串中提取字符串等等。

从当初开始,辞别 copy 正则表达式!

​ 在咱们编码过程中,正则表达式是咱们常来顾客,尤其是表单字段的校验。为了图不便,经常的做法就是去网上进货,而后作为中间商卖给表单。这种做法尽管不便,然而只能满足一般客户(表单)的需要,如果遇到一个大客户须要定制产品(个性的校验规定),到时咱们再去学习如何制作就来不及了,客户不等人,失去了客户不说(我的项目延期),有可能还有扣你尾款(挨下级批斗);

一、基础知识

根本语法

/pattern/[modifiers];
  • pattern:模式
  • modifiers:修饰符

修饰符

修饰符 能够在全局搜寻中不辨别大小写:

修饰符 形容
i 执行对大小写不敏感的匹配。
g 执行全局匹配(查找所有匹配而非在找到第一个匹配后进行)。
m 执行多行匹配。

示例

var str = 'aBc Abcd abcde';
str.match(/bcd/);         // ["bcd"]
str.match(/bcd/g);        // ["bcd", "bcd"]

str.match(/abc/g);        // ["abc"]
str.match(/abc/gi);       // ["aBc", "Abc", "abc"]

咱们在应用过程中,大多数状况都是须要全局匹配的,大小写是否敏感须要依据理论状况来看。

当同时应用多个描述符时,形容的程序无要求:

str.match(/abc/gi);       // ["aBc", "Abc", "abc"]
str.match(/abc/ig);       // ["aBc", "Abc", "abc"]

形容字符

依据正则表达式语法规定,大部分字符仅可能形容本身,这些字符被称为一般字符,如所有的字母、数字等。

元字符就是领有动静性能的特殊字符,须要加反斜杠进行标识,以便与一般字符和转义字符进行区别,JavaScript 正则表达式反对的元字符如表所示。

元字符 形容
. 查找单个字符,除了换行和行结束符
\w 查找单词字符
\W 查找非单词字符
\d 查找数字
\D 查找非数字字符
\s 查找空白字符
\S 查找非空白字符
\b 匹配单词边界
\B 匹配非单词边界
\n 查找换行符
\f 查找换页符
\r 查找回车符
\t 查找制表符
\v 查找垂直制表符
\xxx 查找以八进制数 xxxx 规定的字符
\xdd 查找以十六进制数 dd 规定的字符
\uxxxx 查找以十六进制 xxxx 规定的 Unicode 字符

示例

var str = "hello word 12a3";

str.match(/./gi);           // ["h", "e", "l", "l", "o", "","w","o","r","d"," ","1","2","a","3"]
str.match(/\d/gi);          // ["1", "2", "3"]
str.match(/\D/gi);          // ["h", "e", "l", "l", "o", "","w","o","r","d"," ","a"]
str.match(/\w/gi);          // ["h", "e", "l", "l", "o", "w", "o", "r", "d", "1", "2", "a", "3"]
str.match(/\W/gi);          // [""," "]
str.match(/\s/gi);          // [""," "]
str.match(/\S/gi);          // ["h", "e", "l", "l", "o", "w", "o", "r", "d", "1", "2", "a", "3"]
str.match(/\b/gi);          // ["","", "","", "",""]
str.match(/\B/gi);          // ["","", "","", "","", "","", "",""]

var str = '你好世界! Hello word!'
// 匹配任意 ASCII 字符
str.match(/[\u0000-\u00ff]/g);  // ["!", "","H","e","l","l","o"," ","w","o","r","d","!"]
// 匹配任意双字节的汉字
str.match(/[^\u0000-\u00ff]/g);   // ["你", "好", "世", "界"]
// 匹配大写字母
str.match(/[\u0041-\u004A]/g);  // ["H"]

反复匹配

能够对于某个内容进行屡次匹配

量词 形容
n+ 匹配任何蕴含至多一个 n 的字符串
n* 匹配任何蕴含零个或多个 n 的字符串
n? 匹配任何蕴含零个或一个 n 的字符串
n{x} 匹配蕴含 x 个 n 的序列的字符串
n{x,y} 匹配蕴含起码 x 个、最多 y 个 n 的序列的字符串
n{x,} 匹配蕴含至多 x 个 n 的字符串

示例

var str = 'Hello helllo hehello hehehelllloooo'

str.match(/he/gi);     // ["He", "He", "He", "he", "He", "he", "he", "he"]
str.match(/(he)+/gi);  // ["He", "He", "Hehe", "Hehehehe"]
str.match(/(he)*/gi);  // ["He", "","", "","", "He", "","", "","", "","Hehe","", "","", "","Hehehehe","", "","", "","", "","", "",""]
str.match(/(he)?/gi);  // ["He", "","", "","", "He", "","", "","", "","He","he","", "","", "","He","he","he","he","", "","", "","", "","", "",""]
str.match(/(he){1}/gi); // ["He", "He", "He", "he", "He", "he", "he", "he"]
str.match(/(he){2}/gi); // ["Hehe", "Hehe", "hehe"]
str.match(/(he){2,}/gi); //  ["Hehe", "Hehehehe"]
str.match(/(he){3,4}/gi); // ["Hehehehe"]
str.match(/(he)+l+/gi);   // ["Hell", "Helll", "Hehell", "Hehehehellll"]
str.match(/(he)+l{3,}/gi);   //  ["Helll", "Hehehehellll"]

通过下面的例子,咱们能够发现几个不同的用法能够失去雷同的后果:

  • n+ 等同于 n{1,}
  • n? 等同于 n{0,1}
  • n* 等同于 n{0,}

边界量词

匹配模式的地位

量词 形容
^ 匹配结尾,在多行检测中,会匹配一行的结尾
$ 匹配结尾,在多行检测中,会匹配一行的结尾

示例

var str = 'abc ABC';

/^abc/gi.exec(str);    // ['abc']
/abc$/gi.exec(str);    // ['ABC'] 
/abc/gi.exec(str);     // ['abc']

如果不增加 ^ 和 $,则默认从结尾匹配

匹配范畴

表达式 形容
[abc] 查找方括号之间的任何字符。
[0-9] 查找任何从 0 至 9 的数字。
(x\ y) 查找任何以 \ 分隔的选项。即 x 或 y

示例

var str = 'Hello RegExp 369'

str.match(/[2-8]/gi);     // ["3", "6"]
str.match(/[el]/gi);      // ["e", "l", "l", "e", "E"]
str.match(/[x|5|6]/gi);   // ["x", "6"]
str.match(/[a-h]/gi);     // ["H", "e", "e", "g", "E"]

// 你也能够多个一起应用
str.match(/[2-8a-h]/gi);  // ["H", "e", "e", "g", "E", "3", "6"]

转义字符

通过下面的学习咱们能够看到,在正则表达式中,通过应用一些特殊字符,能够示意不同的匹配模式。如:+、{}、^、? 等。那么当咱们须要匹配这些特殊字符怎么办呢?比如说:匹配‘1 + 2 = 3’中的 “+”,此时咱们就须要对“+”进行本义,即在须要本义的字符后面加上“\”。

var str = '1 + 1 = 3'
str.match(/\+/gi);    // ["+"]

如果只须要匹配一个“+”,当你不进行本义时会报错:

当咱们须要匹配以下特殊字符时,咱们须要进行本义:

$()*+.[]?\^{}|

二、断言

假如有这样一个场景,须要在 ” 今日 18:00-20:00 全场 5 折,洗衣液只有¥19,不要错过哦 ” 中匹配出价格。

价格是由数字组成,如果咱们只通过数字匹配的话,会把其余信息也匹配进去:

var str = '今日 18:00-20:00 全场 5 折,洗衣液只有¥19,不要错过哦';
str.match(/\d+/gi);       // ["18", "00", "20", "00", "5", "19"]

显然只通过数字是不行的,能够留神到,在¥符号前面的才是价格,其余的都不是,如果有什么办法能够匹配指定内容的前面就好了。答案就是断言:

var str = '今日 18:00-20:00 全场 5 折,洗衣液只有¥19,不要错过哦';
str.match(/(?<=¥)\d+/gi);       // ["19"]

断言分为 4 种

符号 形容 含意
reg(?=exp) 正向后行断言 匹配 reg,且 前面 内容 满足exp
reg(?!exp) 负向后行断言 匹配 reg,且 前面 内容 不满足exp
(?<=exp)reg 正向后发断言 匹配 reg,且 后面 内容 满足exp
(?<!exp)reg 负向后发断言 匹配 reg,且 后面 内容 不满足exp

正向后行断言

形如 A(?=B) 的模式,示意匹配到 A,且 A 的前面是 B 的内容。

var str = 'I scream, you scream, we all scream for ice-cream!'
// 匹配 scream 后面的一个单词
str.match(/\w+(?=\sscream)/gi);   // ["I", "you", "all"]

负向后行断言

形如 A(?!B) 的模式,示意匹配到 A,且 A 后面的内容不能满足 B。

var str = 'I scream, you scream, we all scream for ice-cream!';
// 匹配 scream 单词,且前面不能是空格,str.match(/scream(?!\s)/gi);     // ["scream", "scream"]   只能匹配到第一和第二个

正向后发断言

形如 (?<=B)A 的模式,示意匹配到 A,且 A 的后面满足 B。

var str = 'I scream, you scream, we all scream for ice-cream!?'
// 匹配 scream 后的单词
str.match(/(?<=scream\s)\w+/gi);   ["for"]

负向后发断言

形如 (?<!B)A 的模式,示意匹配到 A,且 A 后面的不满足 B。

var str = 'I scream, you scream, we all scream for ice-cream!';
// 匹配 cream,且后面不能为字母
str.match(/(?<!\w)cream/gi);    // ["cream"]   只能匹配到 ice-cream 中的 cream

可能很多人看了之后很容易把这几个记忆混同,这里教大家一个简略的办法了解与记忆:

  • 断言 (exp) 写在前面 就是 匹配前面 的内容,写在后面 就是 匹配后面 的内容
  • 正向 示意 满足 该条件 (符号 = ), 负向 示意 不满足 该条件(符号 ! )
欢送拜访我的集体网站(置信你会喜爱上我的格调):www.dengzhanyong.com
关注我的集体公众号【前端筱园】,不错过我的每一篇推送

三、罕用的正则表达式

  • 正整数: ^\d+$
  • 负整数: ^-\d+$
  • 电话号码: ^+?[\d\s]{3,}$
  • 电话代码: ^+?[\d\s]+(?[\d\s]{10,}$
  • 整数: ^-?\d+$
  • 用户名: ^[\w\d_.]{4,16}$
  • 字母数字字符: ^[a-zA-Z0-9]*$
  • 带空格的字母数字字符: ^[a-zA-Z0-9]*$
  • 明码: ^(?=^.{6,}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$
  • 电子邮件: ^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$
  • IPv4 地址: ^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))*$
  • 小写字母: ^([a-z])*$
  • 大写字母: ^([A-Z])*$
  • 网址: ^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$
  • VISA 信用卡号码: ^(4[0-9]{12}(?:[0-9]{3})?)*$
  • 日期 (MM/DD/YYYY): ^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}$
  • 日期 (YYYY/MM/DD): ^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$

……

四、正则表达式办法

test()

test() 办法用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false。

exec()

exec() 办法用于检索字符串中的正则表达式的匹配。该函数返回一个数组,其中寄存匹配的后果。如果未找到匹配,则返回值为 null。

其余办法应用正则表达式

match()

match() 办法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。

replace()

replace() 办法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

示例

// 将所有的数字替换为 *
var text = 'aaa126bbb34278ccc23';
text.replace(/\d/gi, '*');   // "aaa***bbb*****ccc**"

search()

search() 办法应用表达式来搜寻匹配,而后返回匹配的地位。

示例

// 获取至多呈现两个间断数字的地位
var text = 'ab1cfd3ff452de7532';
text.search(/\d{2,}/gi);   // 9

五、如何写出高效的正则表达式

  1. 误匹配

    对于 +*? 这几个符号须要依据理论场景抉择适合的应用,不要把他们混同

  2. 漏匹配

    如须要匹配 18 位的身份证号,如果这样写 \d{18} 就会呈现漏匹配的状况,因为身份证的最初一位可能是 X,能够这样改良:\d{17}(X|x|\d)

  3. 明确

    通常越简略的正则匹配到的后果就越多,还是拿身份证号来举例,18 个 0 也满足下面的匹配的条件,然而这很显著不是一个省份证号。为了失去更加精确的匹配后果,这就须要要求咱们的正则更加明确。

六、实战演练

咱们来写一个匹配身份证号码的正则,首先须要理解身份证号码的构造。在很久前我写过一篇文章【你晓得身份证是如何防伪的吗?】, 这里我就不具体解说了。

地址码 长度为 6,第一位 1 -9,后 5 位 0 -9

/^[1-9]\d{5}/

年份码 长度为 4,前两位可能是 18、19、20,后两位都是 0 -9

/(18|19|20)\d{2}/

月份码 两位 01-12,日期码 2 位 01-31

/((0[1-9])|1[0-2])(([0-2][1-9])|10|20|30|31)/

程序码 是 3 位 0 - 9 的数字

/\d{3}/

校验码 1 位可能是 0 - 9 或者 X,X 也可能是小写 x

/\d{17}(X|\d|x)$/ 

也能够这样写

/\d{17}[0-9Xx]$/

最初把他们组合起来

/^[1-9]\d{5}(18|19|20|(3\d))\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/

通过这个正则能够判断是否合乎身份证号码的根本要求,然而如果须要更加准确的校验的话,就须要通过编写一些计划来进行校验了。如各省级的地址码为:

华北:北京 11,天津 12,河北 13,山西 14,内蒙古 15

西南:辽宁 21,吉林 22,黑龙江 23

华东:上海 31,江苏 32,浙江 33,安徽 34,福建 35,江西 36,山东 37

华中:河南 41,湖北 42,湖南 43

华南:广东 44,广西 45,海南 46

东北:四川 51,贵州 52,云南 53,西藏 54,重庆 50

东南:陕西 61,甘肃 62,青海 63,宁夏 64,新疆 65

特地:台湾 71,香港 81,澳门 82

有些月份没有 31 号,校验码是否正确等等 …..

欢送拜访我的集体网站(置信你会喜爱上我的格调):www.dengzhanyong.com
关注我的集体公众号【前端筱园】,不错过我的每一篇推送
正文完
 0