共计 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 |
五、如何写出高效的正则表达式
- 误匹配
对于
+
、*
、?
这几个符号须要依据理论场景抉择适合的应用,不要把他们混同 - 漏匹配
如须要匹配 18 位的身份证号,如果这样写
\d{18}
就会呈现漏匹配的状况,因为身份证的最初一位可能是 X,能够这样改良:\d{17}(X|x|\d) - 明确
通常越简略的正则匹配到的后果就越多,还是拿身份证号来举例,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
关注我的集体公众号【前端筱园】,不错过我的每一篇推送