正则表达式是来匹配一个字符串的。“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
关注我的个人公众号【前端筱园】,不错过我的每一篇推送

从现在开始,和copy正则say拜拜!相关推荐

  1. Docker 入门系列(7)- Dockerfile 使用(FROM、RUN、CMD、EXPOSE、ENV、ADD、COPY、ENTRYPOINT、VOLUME、WORKDIR)

    Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 来快速创建自定义的镜像. 1. 基本结构 Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行. ...

  2. JS通过正则限制 input 输入框只能输入整数、小数(金额或者现金)

    第一: 限制只能是整数 [js] view plain copy <input type = "text" name= "number" id = 'nu ...

  3. 谁的bug? 正则 拷贝和粘贴 regulator工具

    写一些数据抓取工具的时候. 我们一般是查看网页的源代码.然后把源代码拷到 regulator哪边去检测.开始写正则. 这个时候一个,难以查觉的错误发生了. 有时候你会发现.你写的正则在regulato ...

  4. java 正则首位8或者9的8位数字_Python 正则表达式re最完整的操作教程

    本文来自Python 官方文档,告诉大家一个好消息,官网有中文版的啦~~ re --- 正则表达式操作 源代码: Lib/re.py 这个模块提供了与 Perl 语言类似的正则表达式匹配操作. 模式和 ...

  5. python进阶(十七)正则json(上)

    1. 一个列表中所有的数字都是重复2次,但是有一个数字只重复了一次. 请找出重复一次的数字,不可以使用内置函数. [2,2,1,1,0,4,3,4,3] 方法1:通过字典计数,找到value等于1的k ...

  6. python3中的正则模块

    本文引至: 正则模块 与正则最相关的应该算是字符串, 但是,在内置的py的str类型中, 并没有内置的正则方法. 我们可以看一下str的基本方法: 我觉得最有用的,应该算find,len,split, ...

  7. 正则数字字母下划线至少两种_8085微处理器中至少两个8位数字

    正则数字字母下划线至少两种 Problem statement: 问题陈述: To find minimum of two 8bit numberusing 8085 microprocessor. ...

  8. 正则验证加js大全,真的很给力!!!很全啊有木有

    [javascript]  view plain copy print ? function f_MobilCheck(as_SourceString) { if(as_SourceString.ma ...

  9. JS 正则表达式(正则匹配RegExp)

    JavaScript实现对象深拷贝的方法(5种) 知识回调(不懂就看这儿!) 场景复现 核心干货 举例引入 关于RegExp对象 语法 修饰符--区分大小写和全局匹配 方括号--查找某个范围内的字符 ...

最新文章

  1. 尽快卸载这两款恶意浏览器插件!已有近50万用户安装
  2. mysql 一次性导入数据库_Mysql 一次性备份导出/导入恢复所有数据库
  3. MultipartResolver
  4. java连接Redis数据库
  5. python可以做什么-Python是什么?用Python可以做什么?
  6. Discuz 论坛实现qq小程序
  7. 关于java的局部知识点总结
  8. Ogre实现简单地形
  9. vue安装vue-pdf(预览pdf)(2021/03/02)
  10. (三)进程各种id:pid、pgid、sid、全局pid、局部pid
  11. math_等式不等式:平方开根号绝对值绝对值不等式放缩基本不等式均值不等式_一元二次方程复根
  12. CSS3鼠标悬停图片360度旋转效果
  13. (数据结构基础)Among the following threaded binary trees (the threads are represented by dotted curves),……
  14. 从字符串中提取IP子串(C语言)
  15. 用动画(animation)做弹力球
  16. 每天一篇论文 323/365 Designing Energy-Efficient Convolutional Neural Networks using Energy-Aware Pruning
  17. 浅说万能头<bits/stdc++.h>
  18. QVegas-一个升级版的TCP Vegas拥塞算法
  19. 什么是BGP多线,与普通双线的区别
  20. 新手避坑,这几种类型的入门吉他,初学者千万不要买!【吉他选购指南】

热门文章

  1. 数据仓库建设方案详细(一):数据仓库建设(上)
  2. RTS/CTS机制以及RTS threshold
  3. 输入三角形的三条边,判断其为什么类型(直角三角形、等边三角形、等腰三角形、普通三角形)的三角形。
  4. 【基于stm32f103C8T6-小程序智能家居项目实战-自绘PCB到实现功能一条龙+30分钟解决-各种bug已修复】
  5. matlab 图像退化,基于matlab的退化图像复原(一)------图像退化处理
  6. HTTP X-Forwarded-For 介绍
  7. Jmeter连接sqlSever踩的坑
  8. PETS渗透测试标准
  9. Multisim、面包板、示波器的使用
  10. ARMv8-M相比ARMv7-M架构优势在哪里?