分类:
2005-09-06 14:25:26
老的方案: 最早出于DEBUG的需要, 曾经用C语言写过打印机文件(以下简称PRT文件)的Parser,
就是要从PRT文件中把数据部分提取出来, 观察RIP生成的色彩数据. 同时验证命令格式是否正确. 很显然, 对于开发者来说,
这些PRT的格式是经常变动的, 而且我要处理的不是一个而是很多种不同格式的PRT文件, C语言的开发周期
源码->编译->运行->调试不十分适合这个目标, 而且这些程序很可能是写了一次就扔掉.
接下来我用flex来解析二进制文件, 虽然这样的用法也不是lex/flex设计者的初衷, 但解析二进制数据是可以的,
flex中能力适中的regexp可以表达我的所需. 这减轻了我一部分负担. 不用在C语言中对文件指针上下腾挪跌打翻滚了.
使用一段时间之后我发现这仍然不是一个理想的方案, 最初我是在flex文件里做几乎所有的工作, 把RLE数据的解压,
数据转换和偏移处理都放在了这里, 但后来发现这样的调试成本比较高, 而我开发的环境又是windows+cygwin下用的flex,
编译用gcc, 因为没有找到其它的windows下flex工具可用. 所以我调试的唯一手段就是printf,
用大量的assert提醒自己非预期条件的发生. assert帮了不少忙, 但往往还需要在出错的时侯知道出错时的周边信息,
比如文件处理到什么位置时出了错误, 所以最经常的做法就是assert失败之后还要回到出错的源代码位置, 再加一个条件判断,
如果失败就用printf把对DEBUG有用的信息显示出来, 往往是ftell(fp).
对flex方案的改进是我只用flex 来解析数据, 不做数据处理了, 解析的结果只是一个文本文件, 其格式如下:
[C] dataoff=102, len=58
意思是对于Cyan, 发现了一行数据, 该行数据在PRT文件中的偏移是102, 数据长度是58. 全部二进制文件Parse完成后的结果是
[C] dataoff=102, len=58
[M] dataoff=187, len=17
[Y] dataoff=192, len=0
[K] dataoff=205, len=18
如此循环. 工作被划分为不同的子任务, 而且由程序的不同部分或不同的程序来完成, 这样简化了很多工作,
而且使得每一个阶段的输出结果都容易验证. 接下来的工作是根据这个文件对数据的描述, 生成CMYK不同色面的数据.
最后的工作是把这4个色面的数据合并成一个TIF文件.
应该说到这一步基本上是一个成本上可以接受的方案了. 解析一个新格式的PRT文件可能只需要写十几二十行的flex 规则. 剩余的处理模块可以通用.
但我还是想更进一步, 用我所精熟的VIM来直接从编辑器里转换图象文件, VIM有接口可以调用外部程序, 也有一个编辑器内置的脚本语言.
不过缺点是这个语言很简单. 不能作为通用的计算机语言来使用(象EMACS中的elisp那样), 比如作用函数参数传递的内容不能包括 的数据.
光这一点我就没法接受, 因为我要处理的正是这样特征的数据, 每一个BYTE数据都可能是从0到255的任何值. 翻文档,
找到其中一段讲 处理的:
===================================================
they are shown as "^@". The translation is done when reading and writing
files. To match a
"CTRL-V 000". This is probably just what you expect. Internally the
character is replaced with a
that typing CTRL-V CTRL-J also inserts a
in the file. {Vi cannot handle
*CR-used-for-NL*
When 'fileformat' is "mac",
characters internally. In the display they are shown as "^M". Otherwise this
works similar to the usage of
When working with expression evaluation, a
matches a
doesn't work there, it only works to match text in the buffer.
*pattern-multi-byte*
Patterns will also work with multi-byte characters, mostly as you would
expect. But invalid bytes may cause trouble, a pattern with an invalid byte
will probably never match.
===================================================
而实际使用上
let @a="a 00b"
echo strlen(@a)
输出结果是1
如果写一个函数:
function! Tmp( dat )
return a:dat
endfunction
然后用这样的方法来调用这样的函数
%s#bin_regexp#=Tmp(submatch(0))#g
按道理来说调用之后缓冲区的内容应该什么都不改变才对, 但实际上不是这样, 函数返回a:dat 就会把第一个 之后的字符丢弃了.
在函数里做手脚的想法又失败了, 我原来的企图是找到这样一个二进制数据, 然后通过 submatch函数把它传递给自定义的函数,
在自定义的函数里处理这个二进制数据, 但既然函数参数不能用来处理 , 我也就只好作罢了.
因为VIM在内部实际把 转换成
但是, 也正因为VIM在内部把 表示为
继续想办法...
VIM作为一个优秀的文本编辑器, 它的很多细微方面的行为仍然是未良好定义的, 比如手册中没有指出下面的替换发生时:
%s#regexp#=UserDefinedFunction()#g
对于每一个找到的regexp, UserDefinedFunction中可以做的事情是有限制的, 一些与当前缓冲区, 光标位置相关的函数应如何表现, 比如line('.'), col('.') 函数是否返回被找到的那个光标位置. 从我的实验结果来看, 的确如此, 但是, 同时我也发现了一些其它的问题.
比如有些命令行为是整个系统内只此一份的, 外面执行的redir如果被某个函数中另一个redir所覆盖, 那可实在是无从查起. 没有地方报告冲突, 错误, 或警告. 而在最新的vim7中, 如果设置了set binary encoding=latin1时, line2byte(1)的返回值竟然是-1, 对同一个文件作同样的设置用vim6.3版本操作返回正确的1.
abaabaaab
%s#a{-}b#g
上面这个标的当然只会发生3次, 对于缓冲区的影响来说. 内容不变. 但
%s#aze{-}b#g
的替换次数就不同了, ze具有限定一个regexp返回范围的作用, 对于aab来说, 整个regexp确实是匹配3个字符aab, 但返回的位置却是第一个a, 而下一次的搜索则从第二个a开始, 所以整个表达式实际上匹配了6次.
所以说zs和ze并不象我自己根据使用总结出来的那样, 仅仅是PERL中(?=)和(?