上一篇文章讲到,从根源上来讲,正则表达式是为了解决文本的查找问题(也称为匹配问题)而诞生的。不过,文本查找方式的历史,要远早于正则表达式。
那么,在正则表达式出现之前,文本查找方式经历了什么演化过程呢?
最后为什么又出现了正则表达式呢?换言之,正则表达式的出现,在文本查找方面,解决了其出现之前所不能解决的什么问题呢?
接下来我们一起来寻找这些问题的答案。
正则表达式其中最基本的功能是为了满足文本查找的需求,而文本查找需求,是一种非常基础、极为常见的需求。
很自然,最先想到和做到的当然就是直接的字面文本查找(简称字面查找)。所谓“字面文本”,指的是用于查找的文本本身就是直接要查找的文本,也就是说,用于查找的文本没有特殊含义,就表示文本本身字面上的含义。
比如要查找文本“张三”,就直接以文本“张三”去进行查找。
但有时我们的查找需求要更为复杂一些,比如不仅要查找“张三”,还有“李三”、“王三”等所有名字中含有“三”这个字的两字姓名。
这种情况下,姓名中的姓就是不确定的了,那怎么办呢?于是比直接的字面查找更为强大、更为方便的另一种间接的查找方式出现了:模式查找方式。
这里出现了一个关键术语:模式。那什么是模式呢?我们知道,工厂生产产品,往往需要先有产品的模板或模具。而模式,就是模板样式或模具样式。
正如符合某种样式的模板或模具,可以用来生产符合这种样式的同一类产品一样,反过来,也可以用某种样式的模板或模具,来检验框定或筛选过滤出哪些产品才是符合这种样式的同一类产品。
比如,以上面这个查找案例来说,从“张三”、“李三”、“王三”等所有名字中含有“三”这个字的两字姓名中抽取出来的查找模式可能是这样的:“?三”,其中的“?”代表所有的单姓。
(为简化讨论,我们这里假定用于查找的文本仅限于姓名,不包括非姓名的其他文本,比如不包括“一二三”这样的文本,而且也暂不考虑两字姓名以外的其他三字姓名、四字姓名等。)
因此,就可以用“?三”这个查找模式来筛选过滤出所有两字姓名中以“三”这个字为名字的姓名。
换句话说,只要是所有两字姓名中以“三”这个字为名字的姓名,都属于同一类姓名,都符合“?三”这个模式,因此都可以通过该模式查找匹配出来。
这里,用于查找的文本模式“?三”,并不是我们要直接查找的文本本身,“?三”中的“?”具有了特殊含义,并不是表示“?”这个字符的字面本身,而是具有了特殊含义——表示所有的单姓,因而“?”在这里具有了一定程度的抽象性、代表性和通用性。
间接模式查找方式目前大致上可划分为“通配符查找方式”和“正则表达式查找方式”两种。
通配符查找方式,在操作系统的文件查找功能中使用得非常普遍。
在这种间接的模式查找方式中,通常使用到的通配符除了上面提到的?号,还有*号。
在操作系统中,一般使用?和*这两个具有抽象性、代表性和通用性的通配符来查找硬盘上的文件。其中,?通配符所规定的查找规则是查找文件名中的单个字符,而*通配符所规定的查找规则是查找文件名中的零个、一个或多个字符。
比如像“data?.dat”这样的查找模式,将可以查找到下列文件名:
data1.dat
datax.dat
dataN.dat
而像“data*.dat”这样的查找模式,则可以查找到下列文件名:
data.dat
data1.dat
data12.dat
datax.dat
dataXYZ.dat
因此,所谓“通配符”,即“通用的查找匹配字符”,就是将某些字符(比如?号和*号)规定为特殊的用于查找文本的通用字符。
用某个通用字符按事先所规定的规则来查找某些常规字符,从而实现“以一对多”(或“以一代多”)、“以简对繁”(或“以简代繁”)地进行查找。
相比较于直接的字面查找方式只能“以一对一”、“以多对多”,或者说“以简对简”、“以繁对繁”,通配符查找模式显然更加抽象化、模式化,所以也就更为通用化、普适化。
然而,尽管通配符查找方式比直接的字面查找方式更强大、更方便、更通用、更普适,但它的功能还是非常有限的,无法精确而灵活地表达更为复杂的查找条件(即查找规则)。
比如无法分组、没有分支结构(即不支持“或运算”)、不支持量词(即不支持循环)、不支持字符组等等。
举个例子,我们不仅要查找两字姓名中的名为“三”字的所有姓名,还要查找两字姓名中的名为“四”字的所有姓名,如果使用通配符查找方式的话,怎么办呢?
由于通配符查找方式没有分支结构,不支持或运算,即不支持类似于“?三|?四”这样的写法(用正则表达式来写的话,就是“.三|.四”),则只能分别进行两次,这显然非常不方便。
再举个例子,如果我们要查找文件系统中命名为DxxxDxxxDxxx.dat的所有文件(其中的x代表任意字符),由于通配符查找方式不支持分组和量词,也就是不支持类似于“(D?{3}){3}”这样的写法(用正则表达式来写的话,就是“(D.{3}){3}”),也是相当麻烦的。
查找需求的多样化和复杂性,呼唤着比通配符查找方式更加强大、更加方便、更加通用、更加普适的查找方式。
于是,能够更为精确、更为灵活地表达更加复杂、更加抽象、更加通用、更加普适的查找条件的全新查找方式——正则表达式就应运而生了。
因此,站在查找方式的历史演化角度上来看,通配符查找方式可认为是正则表达式的前身,或者换言之,正则表达式是通配符查找方式的升级版。
和通配符类似,正则表达式也是以间接的模式来进行文本查找的。显然,相比较于前面所述的“直接字面查找”方式来说,通配符和正则表达式这种以模式进行查找的方式就是“间接模式查找”方式。
正则表达式查找方式相比较于通配符查找方式来说,更为淋漓尽致地体现了“以一对多”(或“以一代多”)、“以简对繁”(或“以简代繁”)的模式查找方式的特点。
不过,既然正则表达式更为抽象化、通用化和普适化,也更为模式化,功能也更为强大、更加灵活,当然也就更为复杂,更难以学习和掌握。
毕竟,强大灵活与简单易用,始终都是一对矛盾。
刨根究底学编程长按扫码 关注本公号好文章就像是好产品一样,是不断迭代、持续完善出来的。
可是,公众号中的文章一旦发布出来后,就不允许再作任何修改了。
因此,如果你期待看到本公众号中系列文章后续的持续改进版本,以及希望能够一起学习交流技术,欢迎扫码加入我的“刨根究底学编程”知识星球,我在那里等待和大家一起共同持续进步。
越早加入越划算哦,因为可能会视情况每1~2周上调10元年费,根据加入人数情况再决定最高封顶年费。
另外,本订阅号文章也会在服务号“笨笨阿林”中转载,虽然服务号一周只能更新一次,不如订阅号及时,但更不容易错过,欢迎一并扫码关注,这样还可以同时阅读我的其他非技术类文章: