ac automata in python
This commit is contained in:
parent
6b50ac0265
commit
9fd6594816
@ -15,16 +15,18 @@ class Node:
|
|||||||
self.children = []
|
self.children = []
|
||||||
|
|
||||||
def insert_child(self, c):
|
def insert_child(self, c):
|
||||||
|
self._insert_child(Node(c))
|
||||||
|
|
||||||
|
def _insert_child(self, node):
|
||||||
"""
|
"""
|
||||||
插入一个子节点
|
插入一个子节点
|
||||||
:param c:
|
:param c:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
v = ord(c)
|
v = ord(node.data)
|
||||||
idx = self._find_insert_idx(v)
|
idx = self._find_insert_idx(v)
|
||||||
length = len(self.children)
|
length = len(self.children)
|
||||||
|
|
||||||
node = Node(c)
|
|
||||||
if idx == length:
|
if idx == length:
|
||||||
self.children.append(node)
|
self.children.append(node)
|
||||||
else:
|
else:
|
||||||
@ -33,6 +35,9 @@ class Node:
|
|||||||
self.children[i] = self.children[i-1]
|
self.children[i] = self.children[i-1]
|
||||||
self.children[idx] = node
|
self.children[idx] = node
|
||||||
|
|
||||||
|
def has_child(self, c):
|
||||||
|
return True if self.get_child(c) is not None else False
|
||||||
|
|
||||||
def get_child(self, c):
|
def get_child(self, c):
|
||||||
"""
|
"""
|
||||||
搜索子节点并返回
|
搜索子节点并返回
|
||||||
|
88
python/36_ac_automata/ac_automata_.py
Normal file
88
python/36_ac_automata/ac_automata_.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: UTF-8 -*-
|
||||||
|
|
||||||
|
from trie_ import Node, Trie
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
|
||||||
|
class ACNode(Node):
|
||||||
|
def __init__(self, c: str):
|
||||||
|
super(ACNode, self).__init__(c)
|
||||||
|
self.fail = None
|
||||||
|
self.length = 0
|
||||||
|
|
||||||
|
def insert_child(self, c: str):
|
||||||
|
self._insert_child(ACNode(c))
|
||||||
|
|
||||||
|
|
||||||
|
class ACTrie(Trie):
|
||||||
|
def __init__(self):
|
||||||
|
self.root = ACNode(None)
|
||||||
|
|
||||||
|
|
||||||
|
def ac_automata(main: str, ac_trie: ACTrie) -> list:
|
||||||
|
root = ac_trie.root
|
||||||
|
build_failure_pointer(ac_trie)
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
p = root
|
||||||
|
for i, c in enumerate(main):
|
||||||
|
while p != root and not p.has_child(c):
|
||||||
|
p = p.fail
|
||||||
|
|
||||||
|
if p.has_child(c): # a char matched, try to find all potential pattern matched
|
||||||
|
q = p.get_child(c)
|
||||||
|
while q != root:
|
||||||
|
if q.is_ending_char:
|
||||||
|
ret.append((i-q.length+1, i))
|
||||||
|
# ret.append(main[i-q.length+1:i+1])
|
||||||
|
q = q.fail
|
||||||
|
p = p.get_child(c)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def build_failure_pointer(ac_trie: ACTrie) -> None:
|
||||||
|
root = ac_trie.root
|
||||||
|
|
||||||
|
# queue: [(node, node.length) ....]
|
||||||
|
node_queue = Queue()
|
||||||
|
node_queue.put((root, root.length))
|
||||||
|
|
||||||
|
root.fail = None
|
||||||
|
while not node_queue.empty():
|
||||||
|
p, length = node_queue.get()
|
||||||
|
for pc in p.children:
|
||||||
|
pc.length = length + 1
|
||||||
|
if p == root:
|
||||||
|
pc.fail = root
|
||||||
|
else:
|
||||||
|
q = p.fail
|
||||||
|
# same as kmp
|
||||||
|
while q != root and not q.has_child(pc.data):
|
||||||
|
q = q.fail
|
||||||
|
|
||||||
|
# cases now:
|
||||||
|
# 1. q == root
|
||||||
|
# 2. q != root and q.has_child(pc.data)
|
||||||
|
if q.has_child(pc.data):
|
||||||
|
pc.fail = q.get_child(pc.data)
|
||||||
|
else:
|
||||||
|
pc.fail = root
|
||||||
|
node_queue.put((pc, pc.length))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ac_trie = ACTrie()
|
||||||
|
ac_trie.gen_tree(['fuck', 'shit', 'TMD', '傻叉'])
|
||||||
|
|
||||||
|
print('--- ac automata ---')
|
||||||
|
m_str = 'fuck you, what is that shit, TMD你就是个傻叉傻叉傻叉叉'
|
||||||
|
print('original str : {}'.format(m_str))
|
||||||
|
|
||||||
|
filter_range_list = ac_automata(m_str, ac_trie)
|
||||||
|
str_filtered = m_str
|
||||||
|
for start, end in filter_range_list:
|
||||||
|
str_filtered = str_filtered.replace(str_filtered[start:end+1], '*'*(end+1-start))
|
||||||
|
|
||||||
|
print('after filtered: {}'.format(str_filtered))
|
Loading…
Reference in New Issue
Block a user