(转)为什么需要正则表达式 by 王珢
为什么需要正则表达式
by 王垠
学习Unix最开头,大家都学过正则表达式(regexp)。可是有没有人考虑过我们为什么需要正则表达式?
正则表达式本来的初衷是用来从无结构的字符串中提取信息,殊不知这正好是Unix的缺陷所在。Unix用无结构的字符串来表示数据,导致了诸多复杂的基于regexp的软件的诞生。sed, AWK, Perl, … 都是为了同样的目的来到这个世界上的。如果不是因为Unix用字符串来表示数据,我们就会拥有按数据结构类型的直接存储,而不需要折腾regexp。正则表达式有它自己的价值(针对自然语言),但是我们其实不需要把它应用到程序语言和操作系统里面。
正则表达式本身用一个字符串来表示,这带来另外一些问题。因为正则表达式的本质不是字符串,而是一个数据结构。学过计算理论的人可能知道这个数据结构叫做NFA(nondeterministic finite automaton,非确定性有限自动机)。所有的数据结构应该由程序语言本身来表示,就像用Java构造一个对象用 new ClassA("a") 一样。但是正则表达式强迫你把这个简单的构造函数调用写成一个字符串。所以在这个比方之下,你得写成new ClassA(\"a\")。这样当你想要组合这些表达式的时候就发现,正则表达式几乎都是不可组合(compose)的。你几乎不可能不能把两个regexp的变量A和B安全拼接成一个,比如用Java的字符串拼接A+B。因为你不知道这两个字符串拼在一起之后,那些稀奇古怪的符号会出现什么交叉反应,使得最后的识别的东西根本不是你想要的。
在正则表达式中,由于正则表达式本身的构造函数与数据本身合并到一起,我们不得不对某些“特殊字符”进行escape。这些特殊字符,其实是用来描述NFA的记号,它们属于更高一层的语言。可是在正则表达式里,它们与NFA节点里的字符混为一谈。比如很简单的一个block comment的正则表达式,却要写成这个样子:
/\\*([^\\*]|[^/])*\\*/
显然这样的表达式很容易出错。 如果我们用程序语言的表达式来构造这个表达式,它应该是这样:
(@... "/*" (@*(@!"*/")) "*/" )
在这个我自己设计的Scheme表达式里,以@开头的标识符都是构造函数。其中@...是构造sequence,@* 是构造一个zero-or-more的匹配,@!构造一个否定匹配。这个表达式是说:“以/ *开头,接着零个或者多个不是* /的字符,最后接着一个* /。这样一来清晰明了,什么表达式在什么“层次”都很清楚,不需要什么反斜杠escape,而且这样的表达式可以compose。比如:
(define reg1 (@... "/*" (@*(@!"*/")) "*/" ))
(define reg2 (@+ "foo"))
(define reg3 (@= "b"))
定义这三个表达式之后,我们之后可以用像(@... reg1 (@or reg2 reg3)) 这样的表达式来连接3个不同的表达式,构造出更大的表达式。这样的构造可以无限的扩展。从这里以及以往的经验,我总结出一个普遍适用的程序设计的教训:尽量不要把多个层次的语言“压缩”到一层。我们也看到正则表达式与“Unix哲学”有很大关系。我没有考古,所以不知道孰先孰后,但是它们肯定有直接的因果关系。两者都是Unix复杂性的来源。
This article was posted at yinwang’s sina blog,
on 2012-05-17.
Though it’s not available now.
(转)为什么需要正则表达式 by 王珢的更多相关文章
- (转)完全用GNU/Linux工作 by 王珢
完全用GNU/Linux工作 王珢 (看完这篇博文,非常喜欢王珢的这篇博客,也我坚定了学gnu/linux的决心,并努力去按照国外的计算机思维模式去学习编程提高自己.看完这篇文章令我热血沸腾 ...
- (转)什么是“黑客” by 王珢
什么是“黑客” by 王垠很多程序员自豪的把自己叫做“黑客”(hacker),把编程叫做 hack.可是殊不知,其实在最高级的程序员眼里,“黑客”其实是一个贬义词.他们更愿意被叫做“程序员”(prog ...
- (转)对博士学位说永别 by 王珢
对博士学位说永别 by 王垠 经过深思熟虑之后,我决定再次“抛弃”我的博士学位.这是我第三次决定离开博士学位,也应该是最后一次了.这应该不是什么惊人的消息,因为我虽然读博士10年了,可是我的目标从来就 ...
- (转)名称和本质 by王珢
名称和本质 by 王垠 我很喜欢 Richard Feynman 写的 <What Do You Care What Other People Think>.在最开头 Feynman 讲到 ...
- (转)小小科学家的归来 by 王珢
小小科学家的归来 by 王垠很多人来信关心我的现状,所以在写别的技术性文章之前,先说说我现在的情况吧.虽然自己追求的东西和经历都比较不同寻常,但是也许可以给奋斗中的人们一些慰藉和鼓励. 首先是超级好消 ...
- (转)我看PhD by 王珢
我看PhD by 王垠 前段时间看了一下这些关于 PhD 的负面信息: 一个专门反对读 PhD 的 BLOG 叫“100 Reasons NOT to Go to Graduate School”(下 ...
- Python 正则表达式入门(初级篇)
Python 正则表达式入门(初级篇) 本文主要为没有使用正则表达式经验的新手入门所写. 转载请写明出处 引子 首先说 正则表达式是什么? 正则表达式,又称正规表示式.正规表示法.正规表达式.规则表达 ...
- python基础之正则表达式
正则表达式语法 正则表达式 (或 RE) 指定一组字符串匹配它;在此模块中的功能让您检查一下,如果一个特定的字符串匹配给定的正则表达式 (或给定的正则表达式匹配特定的字符串,可归结为同一件事). 正则 ...
- SQL中常用模糊查询的四种匹配模式&&正则表达式
执行数据库查询时,有完整查询和模糊查询之分.一般模糊语句如下:SELECT 字段 FROM 表 WHERE 某字段 Like 条件 其中关于条件,SQL提供了四种匹配模式:1.%:表示任意0个或多个字 ...
随机推荐
- 从Eclipse 到Unity(Android)
Eclipse 与Unity之间的交互有以下两种方式: 1.在Eclispe中编写好针对Andorid平台的功能,然后将其制作成库(Library)文件(jar)应用到Unity中; 其中Androi ...
- 412. Fizz Buzz
https://leetcode.com/problems/fizz-buzz/ 没什么好说的,上一个小学生解法 class Solution(object): def fizzBuzz(self, ...
- Swift 备忘单和快速参考
Variables var myInt = var myExplicitInt: Int = // explicit type var x = , y = , z = // declare multi ...
- c++ 陷阱
.c89 c90 gnu90 c99 c11 c++98( default ) c++03 c++11 gnu++11 boolC 标准 does not support the boolean da ...
- Redis安装及实现session共享
一.Redis介绍 1.redis是key-value的存储系统,属于非关系型数据库 2.特点:支持数据持久化,可以让数据在内存中保存到磁盘里(memcached:数据存在内存里,如果服务重启,数据会 ...
- SQL表值函数(上月添加1-28)
ALTER function [dbo].[fn_getdate3] ( ) ) RETURNS @Table_Var TABLE ( LastTime datetime ) as begin Dec ...
- 关于控件的Invoke(...)方法和BeginInvoke(...)方法的区别
这两个方法最主要的区别就是一个是同步,一个是异步,即会阻塞线程,那么阻塞哪个线程呢?我们用代码来分析(工具是VS2010) using System; using System.Collections ...
- cnetos7.0 安装mysql
CentOS 7的yum源中貌似没有正常安装mysql时的mysql-sever文件,需要去官网上下载 [root@localhost ~]# wget http://dev.mysql.com/ge ...
- 【leetcode】Path Sum
题目简述: Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding ...
- JAVA中MAP值保持顺序不变
今天在进行JAVA开发过程中,因需要使用MAP来存放数据,同时希望MAP中KEY的顺序与放入顺序保持一致. 在使用HashMap之后,发现KEY的顺序是乱序的,每次打印还不太一样.上网查询资料之后发现 ...