脚本宝典收集整理的这篇文章主要介绍了正则表达式前端使用手册,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
导读
你有没有在搜索文本的时候绞尽脑汁, 试了一个又一个表达式, 还是不行.
你有没有在表单验证的时候, 只是做做样子(只要不为空就好), 然后烧香拜佛, 虔诚祈祷, 千万不要出错.
你有没有在使用sed 和 grep 命令的时候, 感觉莫名其妙, 明明应该支持的元字符, 却就是匹配不到.
甚至, 你压根没遇到过上述情况, 你只是一遍又一遍的调用 replace 而已 (把非搜索文本全部替换为空, 然后就只剩搜索文本了), 面对别人家的简洁高效的语句, 你只能在心中呐喊, replace 大法好.
为什么要学正则表达式. 有位网友这么说: 江湖传说里, 程序员的正则表达式和医生的处方, 道士的鬼符齐名, 曰: 普通人看不懂的三件神器. 这个传说至少向我们透露了两点信息: 一是正则表达式很牛, 能和医生的处方, 道士的鬼符齐名, 并被大家提起, 可见其江湖地位. 二是正则表达式很难, 这也从侧面说明了, 如果你可以熟练的掌握并应用它, 在装逼的路上, 你将如日中天 (别问我中天是谁……) !
显然, 有关正则表达的介绍, 无须我多言. 这里就借助 Jeffrey Friedl 的《精通正则表达式》一书的序言正式抛个砖.
"如果罗列计算机软件领域的伟大发明, 我相信绝对不会超过二十项, 在这个名单当中, 当然应该包括分组交换网络, Web, Lisp, 哈希算法, UNIX, 编译技术, 关系模型, 面向对象, XML这些大名鼎鼎的家伙, 而正则表达式也绝对不应该被漏掉.
对很多实际工作而言, 正则表达式简直是灵丹妙药, 能够成百倍的提高开发效率和程序质量, 正则表达式在生物信息学和人类基因图谱的研究中所发挥的关键作用, 更是被传为佳话. CSDN的创始人蒋涛先生在早年开发专业软件产品时, 就曾经体验过这一工具的巨大威力, 并且一直印象深刻."
因此, 我们没有理由不去了解正则表达式, 甚至是熟练掌握并运用它.
本文以正则基础语法开篇, 结合具体实例, 逐步讲解正则表达式匹配原理. 代码实例使用语言包括 js, php, python, java(因有些匹配模式, js并未支持, 需要借助其他语言讲解). 内容包括初阶技能和高阶技能, 适合新手学习和进阶. 本文力求简单通俗易懂, 同时为求全面, 涉及知识较多, 共计12k字, 篇幅较长, 请耐心阅读, 如有阅读障碍请及时联系我.
@H_304_25@回顾历史
要论正则表达式的渊源, 最早可以追溯至对人类神经系统如何工作的早期研究. Warren McCulloch 和 Walter PITts 这两位神经大咖 (神经生理学家) 研究出一种数学方式来描述这些神经网络.
1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上, 发表了一篇标题为"神经网事件的表示法"的论文, 引入了正则表达式的概念.
随后, 发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究中. 而 Ken Thompson 又是 Unix 的主要发明人. 因此半个世纪以前的Unix 中的 qed 编辑器(1966 qed编辑器问世) 成了第一个使用正则表达式的应用程序.
至此之后, 正则表达式成为家喻户晓的文本处理工具, 几乎各大编程语言都以支持正则表达式作为卖点, 当然 JavaScript 也不例外.
正则表达式的定义
正则表达式是由普通字符和特殊字符(也叫元字符或限定符)组成的文字模板. 如下便是简单的匹配连续数字的正则表达式:
/[0-9]+/
/d+/
"d" 就是元字符, 而 "+" 则是限定符.
元字符
元字符
描述
.
匹配除换行符以外的任意字符
d
匹配数字, 等价于字符组[0-9]
w
匹配字母, 数字, 下划线或汉字
s
匹配任意的空白符(包括制表符,空格,换行等)
b
匹配单词开始或结束的位置
^
匹配行首
$
匹配行尾
反义元字符
元字符
描述
D
匹配非数字的任意字符, 等价于[^0-9]
W
匹配除字母,数字,下划线或汉字之外的任意字符
S
匹配非空白的任意字符
B
匹配非单词开始或结束的位置
[^x]
匹配除x以外的任意字符
可以看出正则表达式严格区分大小写.
重复限定符
限定符共有6个, 假设重复次数为x次, 那么将有如下规则:
限定符
描述
*
x>=0
+
x>=1
?
x=0 or x=1
{n}
x=n
{n,}
x>=n
{n,m}
n<=x<=m
字符组
[...] 匹配中括号内字符之一. 如: [xyz] 匹配字符 x, y 或 z. 如果中括号中包含元字符, 则元字符降级为普通字符, 不再具有元字符的功能, 如 [+.?] 匹配 加号, 点号或问号.
排除性字符组
[^…] 匹配任何未列出的字符,. 如: [^x] 匹配除x以外的任意字符.
多选结构
| 就是或的意思, 表示两者中的一个. 如: a|b 匹配a或者b字符.
括号
括号 常用来界定重复限定符的范围, 以及将字符分组. 如: (ab)+ 可以匹配abab..等, 其中 ab 便是一个分组.
转义字符
即转义字符, 通常 * + ? | { [ ( ) ] }^ $ . # 和 空白 这些字符都需要转义.
操作符的运算优先级
转义符
(), (?:), (?=), [] 圆括号或方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $ 位置
| "或" 操作
测试
我们来测试下上面的知识点, 写一个匹配手机号码的正则表达式, 如下:
(+86)?1d{10}
① "+86" 匹配文本 "+86", 后面接元字符问号, 表示可匹配1次或0次, 合起来表示 "(+86)?" 匹配 "+86" 或者 "".
② 普通字符"1" 匹配文本 "1".
③ 元字符 "d" 匹配数字0到9, 区间量词 "{10}" 表示匹配 10 次, 合起来表示 "d{10}" 匹配连续的10个数字.
以上, 匹配结果如下:
修饰符
javaScript中正则表达式默认有如下五种修饰符:
g (全文查找), 如上述截图, 实际上就开启了全文查找模式.
i (忽略大小写查找)
m (多行查找)
y (ES6新增的粘连修饰符)
u (ES6新增)
常用的正则表达式
汉字: ^[u4e00-u9fa5]{0,}$
Email: ^w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$
手机号码: ^1d{10}$
身份证号: ^(d{15}|d{17}(d|X))$
中国邮政编码: [1-9]d{5}(?!d) (邮政编码为6位数字)
密码验证
密码验证是常见的需求, 一般来说, 常规密码大致会满足规律: 6-16位, 数字, 字母, 字符至少包含两种, 同时不能包含中文和空格. 如下便是常规密码验证的正则描述:
VAR reg = /(?!^[0-9]+$)(?!^[A-z]+$)(?!^[^A-z0-9]+$)^[^su4e00-u9fa5]{6,16}$/;
正则的几大家族
正则表达式分类
在 linux 和 OSX 下, 常见的正则表达式, 至少有以下三种:
扩展的正则表达式( Extended Regular ExPRession 又叫 Extended RegEx 简称 EREs )
PErl 的正则表达式( Perl Regular Expression 又叫 Perl RegEx 简称 PREs )
正则表达式比较
字符
说明
Basic RegEx
Extended RegEx
python RegEx
Perl regEx
转义
^
匹配行首,例如'^dog'匹配以字符串dog开头的行(注意:awk 指令中,'^'则是匹配字符串的开始)
^
^
^
^
$
匹配行尾,例如:'^、dog$' 匹配以字符串 dog 为结尾的行(注意:awk 指令中,'$'则是匹配字符串的结尾)
$
$
$
$
^$
匹配空行
^$
^$
^$
^$
^string$
匹配行,例如:'^dog$'匹配只含一个字符串 dog 的行
^string$
^string$
^string$
^string$
<
匹配单词,例如:'<frog' (等价于'bfrog'),匹配以 frog 开头的单词
<
<
不支持
不支持(但可以使用b来匹配单词,例如:'bfrog')
>
匹配单词,例如:'frog>'(等价于'frogb '),匹配以 frog 结尾的单词
>
>
不支持
不支持(但可以使用b来匹配单词,例如:'frogb')
<x>
匹配一个单词或者一个特定字符,例如:'<frog>'(等价于'bfrogb')、'<G>'
<x>
<x>
不支持
不支持(但可以使用b来匹配单词,例如:'bfrogb'
()
匹配表达式,例如:不支持'(frog)'
不支持(但可以使用,如:dog
()
()
()
匹配表达式,例如:不支持'(frog)'
不支持(同())
不支持(同())
不支持(同())
?
匹配前面的子表达式 0 次或 1 次(等价于{0,1}),例如:where(is)?能匹配"where" 以及"whereis"
不支持(同?)
?
?
?
?
匹配前面的子表达式 0 次或 1 次(等价于'{0,1}'),例如:'whereis? '能匹配 "where"以及"whereis"
?
不支持(同?)
不支持(同?)
不支持(同?)
?
当该字符紧跟在任何一个其他限制符(*, +, ?, {n},{n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个"o",而 'o+' 将匹配所有 'o'
不支持
不支持
不支持
不支持
.
匹配除换行符('n')之外的任意单个字符(注意:awk 指令中的句点能匹配换行符)
.
.(如果要匹配包括“n”在内的任何一个字符,请使用: [sS]
.
.(如果要匹配包括“n”在内的任何一个字符,请使用:' [.n] '
*
匹配前面的子表达式 0 次或多次(等价于{0, }),例如:zo* 能匹配 "z"以及 "zoo"
*
*
*
*
+
匹配前面的子表达式 1 次或多次(等价于'{1, }'),例如:'whereis+ '能匹配 "whereis"以及"whereisis"
+
不支持(同+)
不支持(同+)
不支持(同+)
+
匹配前面的子表达式 1 次或多次(等价于{1, }),例如:zo+能匹配 "zo"以及 "zoo",但不能匹配 "z"
不支持(同+)
+
+
+
{n}
n 必须是一个 0 或者正整数,匹配子表达式 n 次,例如:zo{2}能匹配
不支持(同{n})
{n}
{n}
{n}
{n,}
"zooz",但不能匹配 "Bob"n 必须是一个 0 或者正整数,匹配子表达式大于等于 n次,例如:go{2,}
不支持(同{n,})
{n,}
{n,}
{n,}
{n,m}
能匹配 "good",但不能匹配 godm 和 n 均为非负整数,其中 n <= m,最少匹配 n 次且最多匹配 m 次 ,例如:o{1,3}将配"fooooood" 中的前三个 o(请注意在逗号和两个数之间不能有空格)
不支持(同{n,m})
{n,m}
{n,m}
{n,m}
x l y
匹配 x 或 y
不支持(同x l y
x l y
x l y
x l y
[0-9]
匹配从 0 到 9 中的任意一个数字字符(注意:要写成递增)
[0-9]
[0-9]
[0-9]
[0-9]
[xyz]
字符集合,匹配所包含的任意一个字符,例如:'[abc]'可以匹配"lay" 中的 'a'(注意:如果元字符,例如:. *等,它们被放在[ ]中,那么它们将变成一个普通字符)
[xyz]
[xyz]
[xyz]
[xyz]
[^xyz]
负值字符集合,匹配未包含的任意一个字符(注意:不包括换行符),例如:'[^abc]' 可以匹配 "Lay" 中的'L'(注意:[^xyz]在awk 指令中则是匹配未包含的任意一个字符+换行符)
[^xyz]
[^xyz]
[^xyz]
[^xyz]
[A-Za-z]
匹配大写字母或者小写字母中的任意一个字符(注意:要写成递增)
[A-Za-z]
[A-Za-z]
[A-Za-z]
[A-Za-z]
[^A-Za-z]
匹配除了大写与小写字母之外的任意一个字符(注意:写成递增)
[^A-Za-z]
[^A-Za-z]
[^A-Za-z]
[^A-Za-z]
d
匹配从 0 到 9 中的任意一个数字字符(等价于 [0-9])
不支持
不支持
d
d
D
匹配非数字字符(等价于 1)
不支持
不支持
D
D
S
匹配任何非空白字符(等价于2)
不支持
不支持
S
S
s
匹配任何空白字符,包括空格、制表符、换页符等等(等价于[ fnrtv])
不支持
不支持
s
s
W
匹配任何非单词字符 (等价于3)
W
W
W
W
w
匹配包括下划线的任何单词字符(等价于[A-Za-z0-9_])
w
w
w
w
B
匹配非单词边界,例如:'erB' 能匹配 "verb" 中的'er',但不能匹配"never" 中的'er'
B
B
B
B
b
匹配一个单词边界,也就是指单词和空格间的位置,例如: 'erb' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的'er'
b
b
b
b
t
匹配一个横向制表符(等价于 x09和 cI)
不支持
不支持
t
t
v
匹配一个垂直制表符(等价于 x0b和 cK)
不支持
不支持
v
v
n
匹配一个换行符(等价于 x0a 和cJ)
不支持
不支持
n
n
f
匹配一个换页符(等价于x0c 和cL)
不支持
不支持
f
f
r
匹配一个回车符(等价于 x0d 和cM)
不支持
不支持
r
r
匹配转义字符本身""
cx
匹配由 x 指明的控制字符,例如:cM匹配一个Control-M 或回车符,x 的值必须为A-Z 或 a-z 之一,否则,将 c 视为一个原义的 'c' 字符
不支持
不支持
cx
xn
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长,例如:'x41' 匹配 "A"。'x041' 则等价于'x04' & "1"。正则表达式中可以使用 ASCII 编码
不支持
不支持
xn
num
匹配 num,其中 num是一个正整数。表示对所获取的匹配的引用
不支持
num
num
[:alnum:]
匹配任何一个字母或数字([A-Za-z0-9]),例如:'[[:alnum:]] '
[:alnum:]
[:alnum:]
[:alnum:]
[:alnum:]
[:alpha:]
匹配任何一个字母([A-Za-z]), 例如:' [[:alpha:]] '
[:alpha:]
[:alpha:]
[:alpha:]
[:alpha:]
[:digit:]
匹配任何一个数字([0-9]),例如:'[[:digit:]] '
[:digit:]
[:digit:]
[:digit:]
[:digit:]
[:lower:]
匹配任何一个小写字母([a-z]), 例如:' [[:lower:]] '
[:lower:]
[:lower:]
[:lower:]
[:lower:]
[:upper:]
匹配任何一个大写字母([A-Z])
[:upper:]
[:upper:]
[:upper:]
[:upper:]
[:space:]
任何一个空白字符: 支持制表符、空格,例如:' [[:space:]] '
[:space:]
[:space:]
[:space:]
[:space:]
[:blank:]
空格和制表符(横向和纵向),例如:'[[:blank:]]'ó'[stv]'
[:blank:]
[:blank:]
[:blank:]
[:blank:]
[:graph:]
任何一个可以看得见的且可以打印的字符(注意:不包括空格和换行符等),例如:'[[:graph:]] '
[:graph:]
[:graph:]
[:graph:]
[:graph:]
[:print:]
任何一个可以打印的字符(注意:不包括:[:cntrl:]、字符串结束符'0'、EOF 文件结束符(-1), 但包括空格符号),例如:'[[:print:]] '
[:print:]
[:print:]
[:print:]
[:print:]
[:cntrl:]
任何一个控制字符(ASCII 字符集中的前 32 个字符,即:用十进制表示为从 0 到31,例如:换行符、制表符等等),例如:' [[:cntrl:]]'
[:cntrl:]
[:cntrl:]
[:cntrl:]
[:cntrl:]
[:punct:]
任何一个标点符号(不包括:[:alnum:]、[:cntrl:]、[:space:]这些字符集)
[:punct:]
[:punct:]
[:punct:]
[:punct:]
[:xdigit:]
任何一个十六进制数(即:0-9,a-f,A-F)
[:xdigit:]
[:xdigit:]
[:xdigit:]
[:xdigit:]
注意
js中支持的是EREs.
当使用 BREs ( 基本正则表达式 ) 时,必须在下列这些符号(?,+,|,{,},(,))前加上转义字符 .
上述[[:xxxx:]] 形式的正则表达式, 是php中内置的通用字符簇, js中并不支持.
linux/osx下常用命令与正则表达式的关系
我曾经尝试在 grep 和 sed 命令中书写正则表达式, 经常发现不能使用元字符, 而且有时候需要转义, 有时候不需要转义, 始终不能摸清它的规律. 如果恰好你也有同样的困惑, 那么请往下看, 相信应该能有所收获.
grep , egrep , sed , awk 正则表达式特点
grep 支持:BREs、EREs、PREs 正则表达式
grep 指令后不跟任何参数, 则表示要使用 "BREs"
grep 指令后跟 ”-E" 参数, 则表示要使用 "EREs"
grep 指令后跟 “-P" 参数, 则表示要使用 "PREs"
egrep 支持:EREs、PREs 正则表达式
egrep 指令后不跟任何参数, 则表示要使用 "EREs"
egrep 指令后跟 “-P" 参数, 则表示要使用 "PREs"
sed 支持: BREs、EREs
sed 指令默认是使用 "BREs"
sed 指令后跟 "-r" 参数 , 则表示要使用“EREs"
awk 支持 EREs, 并且默认使用 "EREs"
正则表达式初阶技能
@H_601_1360@贪婪模式与非贪婪模式
默认情况下, 所有的限定词都是贪婪模式, 表示尽可能多的去捕获字符; 而在限定词后增加?, 则是非贪婪模式, 表示尽可能少的去捕获字符. 如下:
var str = "aaab",
reg1 = /a+/, //贪婪模式
reg2 = /a+?/;//非贪婪模式
console.LOG(str.match(reg1)); //["aaa"], 由于是贪婪模式, 捕获了所有的a
console.log(str.match(reg2)); //["a"], 由于是非贪婪模式, 只捕获到第一个a
实际上, 非贪婪模式非常有效, 特别是当匹配htML标签时. 比如匹配一个配对出现的div, 方案一可能会匹配到很多的div标签对, 而方案二则只会匹配一个div标签对.