君子剑的密室

Friday, July 20, 2007

聊聊sam的structural regular expression

sam是Rob Pike在上世纪90年代初鼓捣出来的编辑器,一般来说,被认为是更接近ed精髓的全屏编辑器。同时,因为sam在设计之初就融入了鼠标的支持(当然,仍然可以以行编辑器的模式运行),所以没有什么在文本区内四处移动的命令(也就是说,没有vi的hjkl w b f t等类似的命令),同时也没有mode(用户的输入会根据是在命令窗口还是文本窗口而被区分为命令还是文本)。

sam和ed相类似的是它也有一个明确的dot概念,始终指向“当前”区域。比方说,当sam利用a命令附加一段文本时,其起始位置就是当前的dot;而当其附加完毕后,dot就会被更新为这段新的文本。再比如,当sam用/.../命令查找某个目标时,dot就会被更新为这个目标(如果找到的话)。因为有了这个dot命令,所以sam的各种命令就可以被级联起来执行:前一个命令操作dot,结束后会提供一个新的dot,后面的命令则依此类推。打个比方,c是更改命令,所以/hello/c/world/就会把前一个命令(查找hello)的dot更改为world,并将world标为新的dot(也就是把hello替换为world)。

再简单说两个命令,就可以聊聊结构化的regexp了。

一个是x命令,格式为x/.../。其作用是在某个文本区域(事先给定)查找所有出现过的某目标,并依次将dot设置为该目标。换言之,x命令提供了一种遍历机制。所以,x/hello/c/world/(,和vi的%含义类似)会讲整个文本中的hello替换为world。

第二个命令是g,格式也是g/.../。和x唯一不同的是,这个命令只查找,却不设置dot。换句话说,它提供的是一个遍历性的条件机制:如果找到...就...。所以,,g/hello/c/world/有可能会把整个文本区域弄成只剩一个单词world,如果文本中原本含有hello的话。

嗯,好了,现在来说说结构化的regexp。用Pike自己给的例子吧。

假设有个电话簿文本文件,里面的内容是
Herbert Tic
44 Turnip Ave., Endive, NJ
Male
201-5555642

Norbert Twinge
16 Potato St., Cabbagetown, NJ
201-5553145
Female

...

每个人的记录是由名称/地址/性别/……/电话之类的项目组成,每个记录的项目个数和顺序也不一定一样,记录和记录之间由空行隔开。假设,这个时候要找某个人的电话号码(假设是要Norbert Twinge的),就可以用下面的命令来得到:, x/(.+\n)+/ g/^Norbert Twinge$/ x/^[0-9]*-[0-9]*\n/ p
第一部份,x/(.+\n)+/相当于将文本按记录分割,依次将dot设置为各个记录;
第二部分g/^Norbert Twinge$/找到该人对应的记录,但是此时的dot仍然没变(是该人的整条记录);
第三部分则只在这个记录范围内匹配出电话号码项。

可以看出,这里的关键就在于,x和g一个查找并且更新dot,而另一个只查找不更新dot从而在文本中建立起了一种结构,并依次完成功能。

Pike在其论文中曾经说过,传统的UNIX工具总是将文件看作由行组成的,并且所有的操作都是在这样一种结构下进行。而sam则可以临时提供其它的结构,因此在某些问题上便更有优势一些。

0 Comments:

Post a Comment

<< Home