前言
正则表达式( ,,regex)使用单个字符串来描述和匹配一系列符合某种句法规则的字符串。此概念来自形式化语言理论,最初由贝尔实验室实现。正则表达式最初在 Perl 中实现,它的推广得益于 UNIX 软件的流行,尤其是 SED,GREP 等。 现在许多编程语言都内置了正则表达式引擎,如 PERL、、、Java、C++ 等。很多文本编辑器也支持正则表达式来进行检索和替换,如 Vim、 Text、 Code 等。正则表达式相关的学习文章网上也是一大推,本文主要记录正则表达式的入门教程和常用公式工具,方便大家活学活用。
为什么要正则表达式?
为什么需要正则表达式 – 王垠
学习 Unix 最开头,大家都学过正则表达式 ()。可是有没有人考虑过我们为什么需要正则表达式?
正则表达式本来的初衷是用来从无结构的字符串中提取信息,殊不知这正好是 Unix 的缺陷所在。Unix 用无结构的字符串来表示数据,导致了诸多复杂的基于 的软件的诞生。sed, AWK, Perl, … 都是为了同样的目的来到这个世界上的。如果不是因为 Unix 用字符串来表示数据,我们就会拥有按数据结构类型的直接存储,而不需要折腾 。正则表达式有它自己的价值(针对自然语言),但是我们其实不需要把它应用到程序语言和操作系统里面。
正则表达式本身用一个字符串来表示,这带来另外一些问题。因为正则表达式的本质不是字符串,而是一个数据结构。学过计算理论的人可能知道这个数据结构叫做 NFA( ,非确定性有限自动机)。所有的数据结构应该由程序语言本身来表示,就像用 Java 构造一个对象用 new (“a”) 一样。但是正则表达式强迫你把这个简单的构造函数调用写成一个字符串。所以在这个比方之下,你得写成 new (“a”)。这样当你想要组合这些表达式的时候就发现,正则表达式几乎都是不可组合 () 的。你几乎不可能不能把两个 的变量 A 和 B 安全拼接成一个,比如用 Java 的字符串拼接 A+B。因为你不知道这两个字符串拼在一起之后,那些稀奇古怪的符号会出现什么交叉反应,使得最后的识别的东西根本不是你想要的。
在正则表达式中,由于正则表达式本身的构造函数与数据本身合并到一起,我们不得不对某些 “特殊字符” 进行 。这些特殊字符,其实是用来描述 NFA 的记号,它们属于更高一层的语言。可是在正则表达式里,它们与 NFA 节点里的字符混为一谈。比如很简单的一个 block 的正则表达式,却要写成这个样子:
/\\*([^\\*]|[^/])*\\*/
显然这样的表达式很容易出错。 如果我们用程序语言的表达式来构造这个表达式,它应该是这样:
(@... "/*" (@*(@!"*/")) "*/")
在这个我自己设计的 表达式里,以 @开头的标识符都是构造函数。其中 @… 是构造 ,@* 是构造一个 zero-or-more 的匹配,@! 构造一个否定匹配。这个表达式是说:“以 / * 开头,接着零个或者多个不是 * / 的字符,最后接着一个 * /。这样一来清晰明了,什么表达式在什么 “层次” 都很清楚,不需要什么反斜杠 ,而且这样的表达式可以 。比如:
(define reg1 (@... "/*" (@*(@!"*/")) "*/")) (define reg2 (@+ "foo")) (define reg3 (@= "b"))
定义这三个表达式之后,我们之后可以用像 (@… reg1 (@or reg2 reg3)) 这样的表达式来连接 3 个不同的表达式,构造出更大的表达式。这样的构造可以无限的扩展。从这里以及以往的经验,我总结出一个普遍适用的程序设计的教训:尽量不要把多个层次的语言 “压缩” 到一层。我们也看到正则表达式与 “Unix 哲学” 有很大关系。我没有考古,所以不知道孰先孰后,但是它们肯定有直接的因果关系。两者都是 Unix 复杂性的来源。
再来看取自 12306 网站的一段代码
// http://www.12306.cn/mormhweb/js/adKyfw.min.js d = d.replace("'", ""); d = d.replace("%", ""); d = d.replace("#", ""); d = d.replace("&", ""); d = d.replace("*", ""); d = d.replace("(", ""); d = d.replace(")", ""); d = d.replace("@", ""); d = d.replace("`", ""); d = d.replace("/", ""); d = d.replace("\", ""); d = d.replace(",", ""); d = d.replace(".", ""); d = d.replace("=", ""); d = d.replace("", "");
上述代码是在过滤掉不合法的搜索字符(姑且不论客户端过滤是否安全), 我们可以用一行正则替换来实现相同的功能:
d = d.replace(/'%#&*()@`/\,.=/g, '');
正则表达式入门教程推荐
感谢作者 从 2006 年开始更新至今,谢谢
正则表达式 30 分钟入门教程 –
正则表达式 – 教程
RegEx
正则表达式在线工具
正则表达式测试工具(在线)
正则表达式在线测试
正则表达式基本语法
定义正则表达式的方式在不同的工具中可能有所差别,但正则表达式内容的语法是一致的。 正则表达式有三类语法结构:
串接(与操作)。相邻的字符默认为串接关系。例如 只能匹配 , 不可匹配 hart。选择(或操作,|)。例如:| 可以匹配 或者 。 选择的优先级级低于串接,因此很多情况下都可以省略括号。数量(限定符)。最常见的数量限定符包括 +, ?, *,分别表示左侧的字符出现一次或更多,不出现或出现一次,不出现或出现任意次。例如 ? 可以匹配 和 。组合(括号,())。组合用来定义操作符的作用范围和优先级。例如 har(ttle)? 可以匹配 和 har,h(a|u)rttle 可以匹配 和 。常用正则表达式
字符 描述 \ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,”n“匹配字符”n“。”n“匹配一个换行符。序列”“匹配”“而” (“则匹配”(“。 ^ 匹配输入字符串的开始位置。如果设置了 对象的 属性,^ 也匹配”n“或”r“之后的位置。 $ 匹配输入字符串的结束位置。如果设置了 对象的 属性,$ 也匹配”n“或”r“之前的位置。 * 匹配前面的子表达式零次或多次。例如,zo 能匹配”z“、”zo“以及”zoo“。等价于 {0,}。 + 匹配前面的子表达式一次或多次。例如,”zo+“能匹配”zo“以及”zoo“,但不能匹配”z“。+ 等价于 {1,}。 ? 匹配前面的子表达式零次或一次。例如,”do(es)?“可以匹配”do“或”does“中的”do“。? 等价于 {0,1}。 {n} n 是一个非负整数。匹配确定的 n 次。例如,”o{2}“不能匹配”Bob“中的”o“,但是能匹配”food“中的两个 o。 {n,} n 是一个非负整数。至少匹配 n 次。例如,”o{2,}“不能匹配”Bob“中的”o“,但能匹配”“中的所有 o。”o{1,}“等价于” o+“。”o{0,}“则等价于”o“。 {n,m} m 和 n 均为非负整数,其中 n
正则表达式
MDN
正则表达式 30 分钟入门教程 –
———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666