通用线程--sed 实例,第3部分( 二 )


过去几个星期,我一直想买一份 Quicken 来结算我的银行帐户 。Quicken 是一个非常好的金融程序,当然会成功地完成这项工作 。但是,经过考虑之后,我觉得自己可以轻易编写某个软件来结算我的支票簿 。我想,毕竟,我是个软件开发人员!我开发了一个很好的小型支票簿结算程序(使用 awk),它通过分析包含我的所有交易的文本文件的语法来计算余额 。略微调整之后,我将其改进,以便可以象 Quicken 那样跟踪不同的贷款和借款类别 。但是,我还要添加一个特性 。最近,我将帐户转移到一家有联机 Web 帐户界面的银行 。有一天,我注意到,这家银行的 Web 站点允许以 Quicken 的 .QIF 格式下载我的帐户信息 。我马上觉得,如果可以将该信息转换成文本格式,那就太棒了 。两种格式的故事
在查看 QIF 格式之前,先看一下我的 checkbook.txt 格式:28 Aug 2000 food - - Y Supermarket 30.94 25 Aug 2000 watr - 103 Y Check 103 52.86

在我的文件中,所有字段都由一个或多个制表符分开,每个交易占据一行 。日期之后的下一个字段列出支出类型(如果是收入项,则为 "-") 。第三个字段列出收入类型(如果是支出项,则为 "-") 。然后,是一个支票号字段(如果为空,则还是 "-"),一个交易完成字段("Y" 或 "N"),一个注释和一个美元金额字段 。现在,让我们看一下 QIF 格式 。当用文本查看器查看下载的 QIF 文件时,它看起来如下:!Type:Bank D08/28/2000 T-8.15 N PCHECKCARD SUPERMARKET ^ D08/28/2000 T-8.25 N PCHECKCARD PUNJAB RESTAURANT ^ D08/28/2000 T-17.17 N PCHECKCARD SUPERMARKET

浏览过文件之后,不难猜出其格式 -- 忽略第一行,其余的格式如下:D<数据>
T<交易量>
N<支票号>
P<描述>
^ (这是字段分隔符)

开始处理
在处理象这样重要的 sed 项目时,不要气馁 -- sed 允许您将数据逐渐修改成最终形式 。在进行当中,可以继续细化 sed 脚本,直到输出与预期的完全一样为止 。无需在试第一次时就保证其完全正确 。要开始,首先创建一个名为 "qiftrans.sed" 的文件,然后开始修改数据:1d /^^/d s/[[:cntrl:]]//g

第一个 "1d" 命令删除第一行,第二个命令从输出除去那些讨厌的 "^" 字符 。最后一行除去文件中可能存在的任何控制字符 。既然在处理外来文件格式,我想消除在中途遇到任何控制字符的风险 。到目前为止,一切顺利 。现在,要向该基本脚本中添加一些处理功能:1d /^^/d s/[[:cntrl:]]//g /^D/ {
s/^D(.*)/1tOUTYtINNYt/
s/^01/Jan/ s/^02/Feb/
s/^03/Mar/ s/^04/Apr/
s/^05/May/ s/^06/Jun/
s/^07/Jul/ s/^08/Aug/
s/^09/Sep/ s/^10/Oct/
s/^11/Nov/ s/^12/Dec/
s:^(.*)/(.*)/(.*):2 1 3: }

首先,添加一个 "/^D/" 地址,以便 sed 只在遇到 QIF 数据字段的第一个字符 "D" 时才开始处理 。当 sed 将这样一行读入其模式空间时,将按顺序执行花括号中的所有命令 。花括号中的第一个命令将把如下行:D08/28/2000

变换成:08/28/2000OUTYINNY

当然,现在的格式还不完美,但没关系 。我们将在进行过程中逐渐细化模式空间的内容 。后面 12 行的最后效果是将数据变换成三个字母的格式,最后一行从数据中除去三个斜杠 。最后得到这一行:Aug 28 2000OUTYINNY

OUTY 和 INNY 字段是占位符,以后将被替换 。现在还不能确定它们,因为如果美元金额为负,将把 OUTY 和 INNY 设置成 "misc" 和 "-",但是,如果美元金额为正,将分别把它们更改成 "-" 和 "inco" 。既然还没有读入美元金额,所以,需要暂时使用占位符 。细化
现在进一步细化:1d /^^/d s/[[:cntrl:]]//g /^D/ {
s/^D(.*)/1tOUTYtINNYt/
s/^01/Jan/ s/^02/Feb/
s/^03/Mar/ s/^04/Apr/
s/^05/May/ s/^06/Jun/

推荐阅读