IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]3.3.2 使用SequenceMatcher对象

    caimouse发表于 2015-09-20 17:41:23
    love 0

    查找最大相同序列

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = [ 1, 2, 3, 5, 6, 4 ]

    s2 = [ 2, 3, 5, 4, 6, 1 ]

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

    matcher = difflib.SequenceMatcher(None, s1, s2)

    print(matcher)

    print(matcher.find_longest_match(0, 6, 0, 6))

    结果输出如下:

    s1 =  [1, 2, 3, 5, 6, 4]

    s2 =  [2, 3, 5, 4, 6, 1]

    s1 == s2 False

     

    <difflib.SequenceMatcher object at 0x0299B4D0>

    Match(a=1, b=0, size=3)

    在这个例子里,使用了库defflib,然后创建两个列表s1和s2,为了找出两个列表里最大的相同的元素长度,需要使用函数find_longest_match的功能。最后输出的结果Match(a=1, b=0, size=3),其Match是命名的元组,a是序列1,也就是列表s1,b是序列2,也就是列表s2,从这里可以看到s1从第1个元素开始,s2从第0个元素开始,就可以达到最大的长度3个元素相同。

     

    跳过指定的字符

    在某种情况之下进行文本比较时,需要把空格去掉,只比较关心的字符,就可以采用过虑函数的功能。

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = ' abcd'

    s2 = 'abcd abcd'

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

    print('丢掉不需要空格字符:')

    matcher = difflib.SequenceMatcher(lambda x: x in ' ', s1, s2)

    print(matcher)

    print(matcher.find_longest_match(0, 5, 0, 9))

     

    print('没有丢掉不需要字符:')

    matcher = difflib.SequenceMatcher(None, s1, s2)

    print(matcher)

    print(matcher.find_longest_match(0, 5, 0, 9))

    输出结果如下:

    s1 =   abcd

    s2 =  abcd abcd

    s1 == s2 False

     

    丢掉不需要空格字符:

    <difflib.SequenceMatcher object at 0x0272B4B0>

    Match(a=1, b=0, size=4)

    没有丢掉不需要字符:

    <difflib.SequenceMatcher object at 0x0272BCF0>

    Match(a=0, b=4, size=5)

     

    在这个例子里,使用SequenceMatcher对象两种不同的构造形式,主要表示在isjunk是否跳过的值,这是使用函数对象来实现的,lambda是语句里声明函数的方式,x是SequenceMatcher对象进行比较时传递进来的值,然后判断x是否为空格,如果是就返回True,这样SequenceMatcher对象就知道这个字符不用比较,如果返回False,就进行比较,这就是默认的情况None。因此,可以看到第一个有跳过空格的比较,是从a指向的字符第1个字符开始,而不是从0开始,从而在b指向的字符串0位置就可以匹配成功了。而第二个没有跳过空格时,a是指向的字符串是从0开始,而b指向字符串进行匹配是从4开始,也就是从空格字符开始,匹配最长的长度是5。

     

    使用函数set_seqs(a, b)

    当你创建一个SequenceMatcher对象之后,并且使用之后又想接着比较另外一对新的序列对象,就可以使用此函数来进行设置新的比较对象,这样不用再次创建SequenceMatcher对象。

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = ' abcd'

    s2 = 'abcd abcd'

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

    print('丢掉不需要空格字符:')

    matcher = difflib.SequenceMatcher(lambda x: x in ' ', s1, s2)

    print(matcher)

    print(matcher.find_longest_match(0, 5, 0, 9))

     

    print('使用set_seqs(a, b):')

    s3 = 'abcd'

    s4 = 'abc abcd'

     

    matcher.set_seqs(s3, s4)

    print(matcher)

    print(matcher.find_longest_match(0, 4, 0, 8))

    结果输出如下:

    s1 =   abcd

    s2 =  abcd abcd

    s1 == s2 False

     

    丢掉不需要空格字符:

    <difflib.SequenceMatcher object at 0x029BB4D0>

    Match(a=1, b=0, size=4)

    使用set_seqs(a, b):

    <difflib.SequenceMatcher object at 0x029BB4D0>

    Match(a=0, b=4, size=4)

    在这个例子里可以看到,使用函数set_seqs(a, b)之后,就可以重新对新的序列s3,s4进行比较了,而不必再创建一个新的SequenceMatcher对象。

     

    同一个序列跟不同其它序列进行比较,使用函数set_seq1(a)、set_seq2(b) 

    如果在一个序列与多个序列进行比较,可以固定一个序列不变,只变第一或第二个序列,就可以使用set_seq1(a)或者set_seq2(b)函数。

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = ' abcd'

    s2 = 'abcd abcd'

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

    print('丢掉不需要空格字符:')

    matcher = difflib.SequenceMatcher(lambda x: x in ' ', s1, s2)

    print(matcher)

    print(matcher.find_longest_match(0, 5, 0, 9))

     

    print('使用set_seq1(a):')

    s3 = 'abcd'

     

    matcher.set_seq1(s3)

    print(matcher)

    print(matcher.find_longest_match(0, 4, 0, 9))

     

    s4 = 'abc abcd'

    matcher.set_seq2(s4)

    print(matcher)

    print(matcher.find_longest_match(0, 4, 0, 8))

    结果输出如下:

    s1 =   abcd

    s2 =  abcd abcd

    s1 == s2 False

     

    丢掉不需要空格字符:

    <difflib.SequenceMatcher object at 0x029BB4D0>

    Match(a=1, b=0, size=4)

    使用set_seq1(a):

    <difflib.SequenceMatcher object at 0x029BB4D0>

    Match(a=0, b=0, size=4)

    <difflib.SequenceMatcher object at 0x029BB4D0>

    Match(a=0, b=4, size=4)

    在这个例子里,通过切换不同的序列进行比较,从而得不同的输出结果。这样的速度应比重头创建一个SequenceMatcher要快一些,因为其中一个不用重新计算了。

     

    get_matching_blocks()函数的使用

    这个函数主要用获取a和b比较序里所有相同的交集,通过一个三元组保存在一个列表里返回。

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = ' abcd 123 321'

    s2 = 'abcd abcd 123321'

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

    print('丢掉不需要空格字符:')

    matcher = difflib.SequenceMatcher(lambda x: x in ' ', s1, s2)

    print(matcher)

    print(matcher.get_matching_blocks())

    结果输出如下:

    s1 =   abcd 123 321

    s2 =  abcd abcd 123321

    s1 == s2 False

     

    丢掉不需要空格字符:

    <difflib.SequenceMatcher object at 0x0278B4D0>

    [Match(a=1, b=0, size=5), Match(a=6, b=10, size=3), Match(a=10, b=13, size=3), Match(a=13, b=16, size=0)]

    在这个例子里,从返回的结果来看,就是在序列a[1:6]与b[0:5]相同,也就是字符串“abcd ”相同;后面依次是a的6位置与b的10位置有3个字符相同,a的10位置与b的13位置有3个字符相同,最后一个表示a序列为13个字符长度,b序列为16个字符长度,size等于0用来表示最后一个三元组。

     

    使用get_opcodes()函数

    通过这个函数就可以查看两个序列进行比较的过程。

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = ' abcd 123 321'

    s2 = 'abcd abcd 123321'

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

     

    matcher = difflib.SequenceMatcher(None, s1, s2)

    print(matcher)

     

    for tag, i1, i2, j1, j2 in matcher.get_opcodes():

        print('{:7}   a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format(

            tag, i1, i2, j1, j2, s1[i1:i2], s2[j1:j2]))

    结果输出如下:

    s1 =   abcd 123 321

    s2 =  abcd abcd 123321

    s1 == s2 False

     

    <difflib.SequenceMatcher object at 0x0298B4D0>

    insert    a[0:0] --> b[0:4]       '' --> 'abcd'

    equal     a[0:9] --> b[4:13] ' abcd 123' --> ' abcd 123'

    delete    a[9:10] --> b[13:13]      ' ' --> ''

    equal     a[10:13] --> b[13:16]    '321' --> '321'

    从上面结果来看,从s1字符串变成s2字符串需要的操作过程,先是从s1的0位置插入4个字符’abcd’,接着s1[0:9]与s2[4:13]部分相同,接着把s1[9:10]部分删除,最后是s1[10:13]和s2[13:16]相同部分。

     

    使用get_grouped_opcodes(n=3)函数

    这个函数是通过n来设置最长匹配值,默认为3个字符。

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = ' abcd 123 321'

    s2 = 'abcd abcd 123321'

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

    matcher = difflib.SequenceMatcher(None, s1, s2)

    print(matcher)

     

    for i in matcher.get_grouped_opcodes(1):

        print(i)

        print(':')

     

    print('默认:')

    for i in matcher.get_grouped_opcodes(9):

        print(i)

    结果输出如下:

    s1 =   abcd 123 321

    s2 =  abcd abcd 123321

    s1 == s2 False

     

    <difflib.SequenceMatcher object at 0x0279B4D0>

    [('insert', 0, 0, 0, 4), ('equal', 0, 1, 4, 5)]

    :

    [('equal', 8, 9, 12, 13), ('delete', 9, 10, 13, 13), ('equal', 10, 11, 13, 14)]

    :

    默认:

    [('insert', 0, 0, 0, 4), ('equal', 0, 9, 4, 13), ('delete', 9, 10, 13, 13), ('equal', 10, 11, 13, 14)]

    从结果上看,这个函数返回一个列表,列表里包含多个元组。参数n的值决定最长搜索的长度。

     

    使用ratio() 、quick_ratio()、real_quick_ratio()函数

    计算两个比较序列的相似程度。

    例子:

    #python3.4.3

     

    import difflib

     

    s1 = ' abcd 123 321'

    s2 = 'abcd abcd 123321'

     

    print('s1 = ', s1)

    print('s2 = ', s2)

    print('s1 == s2', s1 == s2)

    print('')

     

    matcher = difflib.SequenceMatcher(None, s1, s2)

    print(matcher)

    print('ratio():', matcher.ratio())

    print('quick_ratio():', matcher.quick_ratio())

    print('real_quick_ratio():', matcher.real_quick_ratio())

    结果输出如下:

    s1 =   abcd 123 321

    s2 =  abcd abcd 123321

    s1 == s2 False

     

    <difflib.SequenceMatcher object at 0x0298B4B0>

    ratio(): 0.8275862068965517

    quick_ratio(): 0.8275862068965517

    real_quick_ratio(): 0.896551724137931

    从结果来看,ratio的结果与quick_ratio的结果是非常接近的,但quick_ratio的速度更快一些,而real_quick_ratio的结果就差别比较大一些,但速度会更快。

     


    蔡军生  微信号:shenzhencai  深圳



沪ICP备19023445号-2号
友情链接