为什么需要正则表达式

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 王珢的更多相关文章

  1. (转)完全用GNU/Linux工作 by 王珢

    完全用GNU/Linux工作 王珢      (看完这篇博文,非常喜欢王珢的这篇博客,也我坚定了学gnu/linux的决心,并努力去按照国外的计算机思维模式去学习编程提高自己.看完这篇文章令我热血沸腾 ...

  2. (转)什么是“黑客” by 王珢

    什么是“黑客” by 王垠很多程序员自豪的把自己叫做“黑客”(hacker),把编程叫做 hack.可是殊不知,其实在最高级的程序员眼里,“黑客”其实是一个贬义词.他们更愿意被叫做“程序员”(prog ...

  3. (转)对博士学位说永别 by 王珢

    对博士学位说永别 by 王垠 经过深思熟虑之后,我决定再次“抛弃”我的博士学位.这是我第三次决定离开博士学位,也应该是最后一次了.这应该不是什么惊人的消息,因为我虽然读博士10年了,可是我的目标从来就 ...

  4. (转)名称和本质 by王珢

    名称和本质 by 王垠 我很喜欢 Richard Feynman 写的 <What Do You Care What Other People Think>.在最开头 Feynman 讲到 ...

  5. (转)小小科学家的归来 by 王珢

    小小科学家的归来 by 王垠很多人来信关心我的现状,所以在写别的技术性文章之前,先说说我现在的情况吧.虽然自己追求的东西和经历都比较不同寻常,但是也许可以给奋斗中的人们一些慰藉和鼓励. 首先是超级好消 ...

  6. (转)我看PhD by 王珢

    我看PhD by 王垠 前段时间看了一下这些关于 PhD 的负面信息: 一个专门反对读 PhD 的 BLOG 叫“100 Reasons NOT to Go to Graduate School”(下 ...

  7. Python 正则表达式入门(初级篇)

    Python 正则表达式入门(初级篇) 本文主要为没有使用正则表达式经验的新手入门所写. 转载请写明出处 引子 首先说 正则表达式是什么? 正则表达式,又称正规表示式.正规表示法.正规表达式.规则表达 ...

  8. python基础之正则表达式

    正则表达式语法 正则表达式 (或 RE) 指定一组字符串匹配它;在此模块中的功能让您检查一下,如果一个特定的字符串匹配给定的正则表达式 (或给定的正则表达式匹配特定的字符串,可归结为同一件事). 正则 ...

  9. SQL中常用模糊查询的四种匹配模式&&正则表达式

    执行数据库查询时,有完整查询和模糊查询之分.一般模糊语句如下:SELECT 字段 FROM 表 WHERE 某字段 Like 条件 其中关于条件,SQL提供了四种匹配模式:1.%:表示任意0个或多个字 ...

随机推荐

  1. PHP生成日历数组,减少分页

    2016年11月14日 20:45:41 星期一 情景, 每个用户设置定投, app的屏幕比较小, 觉得常规的线性分页下拉不是很方便 吧列表改为日历格式的会更方便执行, 每年12个月, 总过12个页面 ...

  2. ORACLE发送带附件邮件的二三事之一

    在oracle使用过程中,我们可以通过pl/sql生成数据文件,也可以通过spool on spool off生成,但某些环境下,我们需要通过存储过程处理数据,数据处理完,需要自动生成数据文件,手工导 ...

  3. sublime text 2 快捷键

    快捷键 功能 ctrl+shift+n 打开新Sublime ctrl+shift+w 关闭Sublime,关闭所有打开文件 ctrl+shift+t 重新打开最近关闭文件 ctrl+n 新建文件 c ...

  4. 一个简单的判断浏览器是否为IE9以下的方法

    if(!-[1,]){ //是IE placeHolderIE9_(); }else{ //非IE if(navigator.userAgent.indexOf("MSIE 9.0" ...

  5. ProtocolBuffers-3 For Objective C (2)-进阶

    先介绍几个常用关键字: equired前缀表示该字段为必要字段,既在序列化和反序列化之前该字段必须已经被赋值.与此同时,在Protocol Buffer中还存在另外两个类似的关键字,optional和 ...

  6. luac++

    Cocos2d-x下Lua调用自定义C++类和函数的最佳实践 洪亮 305 2014年08月09日 发布   1 推荐 21 收藏,14.9k 浏览 关于cocos2d-x下Lua调用C++的文档看了 ...

  7. winform中选择文件获取路径

    private void button1_Click(object sender, EventArgs e) { //此时弹出一个可以选择文件的窗体 OpenFileDialog fileDialog ...

  8. vue2.0 组件之间的数据传递

    组件间的数据传递// 父组件<template><div class="order"><dialog-addpro v-on:closedialog= ...

  9. vs2016x64&&qt5.7.1编译osg3.4.0&&osgEarth2.7

    此文仅备忘: 1.安装VS2013_Cn_Ult 2.安装qt-opensource-windows-x86-msvc2013_64-5.7.1 设置环境变量QTDIR,并将其bin加入到path中. ...

  10. response生成图片验证码

    新建一个java web工程 src 目录下xieyuan包MyServlet.java文件(Servlet文件) package xieyuan; import java.awt.Color; im ...