Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2414336
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: Python/Ruby

2012-04-07 21:49:30

lookup table(查表法)

 

转自:

 

在讲lookup table技术之前,先讲一下回溯引用
       
回溯引用对于大家来说并不陌生,会经常用于 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取上月的月份
       
        UNIX
下一般都没有GNU date,即便有GNU date,在某些时间点(331)上进行取上月操作(-1 month)的时候也有问题

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:文本处理
       

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技术的基本做法都是先构造一个列表,然后用回溯引用定位,从而得到我们需要的值

阅读(7868) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~