ahocorasick库的应用

ahocorasick库的应用

ahocorasick库的官方文档:https://pyahocorasick.readthedocs.io/en/latest/

Pyahocorasick是一个快速且节省内存的库,用于精确或模糊的多模式字符串搜索,这意味着您可以在输入文本中同时发现多个关键字符串。字符串“index”可以提前构建并保存(作为pickle)到磁盘,以便重新加载和以后重用。该库提供了一个ahocorasick Python模块,您可以将其用作普通的类似dict的Trie树,也可以将Trie树转换为自动机,以实现高效的Aho-Corasick搜索。

练习题:(这题的本意是让练人者自己实现Aho-Corasick搜索,怎奈自己的水平不行,理解不了这算法,只能用现成的库实现,做为记录。)

下面是程序的简单输入测试数据,根据这个测试数据,展开题目(因为题目太长了)。

输入:

6
a b c aa d b
1 2 3 4 5 6
3
1 5 caaab
0 4 xyz
2 4 bcdybc

输出:

0 19

n=6,这代表关键字genes有6个。

genes=[‘a’, ‘b’, ‘c’, ‘aa’, ‘d’, ‘b’],这是关键字

health=[1, 2, 3, 4, 5, 6],这是值

s=3,代表下面要进行3次关键字的搜索

[1, 5, ‘caaab’],first=1,last=5,d=’caaab’,first代表搜索关键字的开始位置(包含该位置,位置从0开始),last代表搜索关键字的结束位置(包含该位置,位置从0开始),d代表搜索字符串

[0,4, ‘xyz],同上

[2, 4, ‘bcdybc’],同上

关键字和值是对应的(可以把其看成是字典,但是要注意其中是有重复的关键字,但是拥有不同的值),关键字在first和last的范围内,查找d中出现的次数,并计算关键字对应的值的总和。

因此’caaab’的总合是3+4+4+2+6=19,其中的’aaa’要分解成’aaa’和’aaa‘,所以是两个4。因为first的位置是1,所以位置为0的关键字’a’就被跳过了。同时因为b有两个值,一个是2,另一个是6,而取值范围还包含了这两个值的位置,所以这两个值都要计算。

而’xyz’没有对应的关键字,因此总合是0

而’bcdybc’中只有部分关键字存在,所以总合是3+5+3=11

题目:在s次的搜索中找出最小值和最大值。

调用ahocorasick库的程序:

import ahocorasick
def func2():
    trie=ahocorasick.Automaton()

    n = int(input().strip())

    genes = input().rstrip().split()

    health = list(map(int, input().rstrip().split()))

    s = int(input().strip())
    i=0

    #向trie中添加关键字,关键字是列表的原因是要输入重复的关键字,而且ahocorasick的实例中输入重复的关键字时,会将旧的值覆盖。add_word(关键字,值)
    for k,v in zip(genes,health):
        if k in trie.keys():
            trie.get(k).append((i,v,))
        else:
            trie.add_word(k,[(i,v,)])
        i = i + 1

    # 使trie变成Aho-Corasick自动机,让trie可以进行 Aho-Corasick搜索
    trie.make_automaton()
    result = []
    for s_itr in range(s):
        first_multiple_input = input().rstrip().split()

        first = int(first_multiple_input[0])

        last = int(first_multiple_input[1])

        d = first_multiple_input[2]
        count_genes=0
        #在trie中进行 Aho-Corasick搜索,d就是被搜索的字符串,trie.iter(d)可以返回所有找到的关键字,其返回值是(位置,值)这样的元祖。位置是关键字在d中的位置,就是关键字对应的值。
        for i in trie.iter(d):
            for j in i[1]:
                if first<=j[0]<=last:
                    count_genes+=j[1]
        result.append(count_genes)
    print(f'{min(result)} {max(result)}')
test中有三个测试数据,结果如下:
    result={
        'test_data0.txt':'0 19',
        'test_data1.txt':'11674463 11674463',
        'test_data2.txt':'15806635 20688978289',
    }

如果用暴力的比对方式的话,后两个测试数据运行时间可高达十几分钟,使用 Aho-Corasick搜索,1分钟内就可以得到结果。

这篇算法的论文可以让我们更好的理解Aho-Corasick搜索,但是我放弃了。

Comments are closed.