首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

lookup table(查表法)

lookup table(查表法)

在讲lookuptable技术之前,先讲一下“回溯引用”
        回溯引用对于大家来说并不陌生,会经常用于s/REGEXP/REPLACEMENT/ 中REPLACEMENT部分
但回溯引用并不是只能用于REPLACEMENT部分,在REGEXP中也是可以使用的。
例1:找出100以内,个位与十位相同的2位数

1.
ly5066113@ubuntu:~$seq 100 | sed -n '/^\(.\)\1$/p'

2.
11

3.
22

4.
33

5.
44

6.
55

7.
66

8.
77

9.
88

10.
99

我们可以看到,这个问题利用回溯引用很容易解决。
        \1表示前面\(.\)中内容,换种说法就是\1与前面\(.\)是相同的,那么就是个位与十位相同了
在理解了REGEXP中的回溯引用之后,我们来看看lookup table技术
        lookup table就是回溯引用的方式进行前后定位,然后取出我们需要内容
例2:AIX下怎么用DATE取上月的月份
        http://bbs.chinaunix.net/viewthread.php?tid=995655
        UNIX下一般都没有GNU date,即便有GNU date,在某些时间点(如3月31号)上进行取上月操作(-1month)的时候也有问题

1.
ly5066113@ubuntu:~$date +%m

2.
08

3.
ly5066113@ubuntu:~$date +%m | sed's/$/b12a01a02a03a04a05a06a07a08a09a10a11a12/;s/^\(..\)b.*\(..\)a\1.*/\2/'

4.
07

我们来看看这段代码是如何工作的:
        1、构造一个列表,字母a左边的2位数字是右边2位数字的上一个月
        2、利用lookup table取出上一个月

        pattern space初始为:
        08
        第一个s命令处理后pattern space变为:
        08b12a01a02a03a04a05a06a07a08a09a10a11a12
        下面我们重点来看看第二个s命令是怎么工作的:
        s/^\(..\)b.*\(..\)a\1.*/\2/
        将pattern space里面的内容按照上面的正则表达式进行分解
        ^\(..\)             08
        b.*                 b12a01a02a03a04a05a06a
        \(..\)              07
        a\1                 a08
        .*                  a09a10a11a12
        整个过程就是通过第一个括号里面的内容 08 ,定位到后面的 a08 ,从而取出它前面的2位数字07 ,也就是第二个括号里的内容 \2
        这种方法就称之为 lookup table


        例3:文本处理
        http://bbs.chinaunix.net/viewthread.php?tid=1385995

1.
ly5066113@ubuntu:~$cat urfile

2.
172.27.38.0&1=99&2=100

3.
192.168.9.2&1=100&3=111

4.
202.96.64.68&1=99&2=1&3=111

5.
202.96.69.38&1=99&3=111&4=110

6.
202.77.88.99&1=99&2=111&3=66&4=100&5=44

7.
ly5066113@ubuntu:~$sed -r's/&/\n1\n2\n3\n4\n5&/;:a;s/\n(.)(.*)&\1=([^&]+)/\t\3\2/;ta;s/\n./\t0/g'urfile

8.
172.27.38.0    99      100    0       0       0

9.
192.168.9.2    100     0      111     0       0

10.
202.96.64.68   99      1       111    0       0

11.
202.96.69.38   99      0       111    110     0

12.
202.77.88.99   99      111     66     100     44

整体思路,用原贴中dream3401的描述:
        1、产生1,2,3,4,5的"坐标"
        2、对每天"有坐标的赋值"中的值代入坐标
        3、对没有"赋值的坐标"代入0

        我们以第一行数据为例,看看这段代码是怎么工作的:
        pattern space初始为:
        172.27.38.0&1=99&2=100
        s/&/\n1\n2\n3\n4\n5&/后:
        172.27.38.0\n1\n2\n3\n4\n5&1=99&2=100
        s/\n(.)(.*)&\1=([^&]+)/\t\3\2/后:
        172.27.38.0    99\n2\n3\n4\n5&2=100
        s命令执行成功,t命令执行,跳转到标签a处,再次执行s/\n(.)(.*)&\1=([^&]+)/\t\3\2/:
        172.27.38.0     99     100\n3\n4\n5
        s命令执行成功,t命令执行,跳转到标签a处,再次执行s/\n(.)(.*)&\1=([^&]+)/\t\3\2/,s命令执行失败,无替换
        t命令不执行,执行s/\n./\t0/g:
        172.27.38.0     99     100     0      0       0

        对于以上步骤,第一个s命令和最后一个s命令都不难理解,关键是中间的这句:
        s/\n(.)(.*)&\1=([^&]+)/\t\3\2/
        那我们以第一次的执行为例,将pattern space里面的内容按照上面的正则表达式进行分解
        \n(.)               \n1
        (.*)                \n2\n3\n4\n5
        &\1=                &1=
        ([^&]+)             99
        利用第一个括号的数字1,定位到后面&1=中的数字1,从而取出=号后面的数字99
        172.27.38.0               \n1\n2\n3\n4\n5&1=99               &2=100
        172.27.38.0    99\n2\n3\n4\n5                              &2=100
        此正则表达式在工作的过程中,开头的172.27.38.0 和结尾的 &2=100 都是没有处理的,处理的只是中间的一部分
例3和例2虽然都是用的lookup table技术,但思路梢有不同。
例2是构造一个列表,然后从列表中lookup出想要的值
例1也是构造一个列表,但是将外面的值填充到列表中
无论是那种方式,lookup table技术的基本做法都是先构造一个列表,然后用回溯引用定位,从而得到我们需要的值

继承事业,薪火相传
返回列表