正则表达式教程_正则表达式子表达式_正规表达式

前言

正则表达式( ,,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

声明:1、本内容转载于网络,版权归原作者所有!2、本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。3、本内容若侵犯到你的版权利益,请联系我们,会尽快给予删除处理!