AC 算法,返回命中标签

AC自动机算法

简介

Aho-Corasick算法简称AC算法,通过将模式串预处理为确定有限状态自动机,扫描文本一遍就能结束。其复杂度为O(n),即与模式串的数量和长度无关。

1、简要概述

什么是AC自动机算法?
​ AC自动机算法是一种多模式字符串匹配算法,什么是多模式?从单模式说起,举个kmp算法的例子,单模式就是利用kmp算法验证某个敏感词在一个字符串内是否存在;多模式是说验证多个敏感词在一个字符串内是否存在。如果使用kmp来做的话,依次遍历多个敏感词,每个敏感词使用kmp验证,当敏感词数量很多的时候效率很低,这时候就用到AC自动机算法了。

​ 为什么AC自动机算法效率高?
​ 结论:其能在约为O(n) 的时间复杂度内完成对多个敏感词的查找,而且其时间复杂度只跟搜索串的长度(n)有关,跟敏感词的数量并无关联,原理和kmp算法的next数组类似,只不过这里用的是fail指针。

2、调用方法
/**
 * 大小写敏感
 * @return
 */
public Trie caseInsensitive()
{
    this.trieConfig.setCaseInsensitive(true);
    return this;
}

/**
 * 不允许模式串在位置上前后重叠
 * @return
 */
public Trie removeOverlaps()
{
    this.trieConfig.setAllowOverlaps(false);
    return this;
}

/**
 * 只匹配完整单词
 * @return
 */
public Trie onlyWholeWords()
{
    this.trieConfig.setOnlyWholeWords(true);
    return this;
}
3、匹配过程

自动机从根节点0出发

1、首先尝试按success表转移(图中实线)。按照文本的指示转移,也就是接收一个u。此时success表中并没有相应路线,转移失败。

2、失败了则按照failure表回去(图中虚线)。按照文本指示,这次接收一个s,转移到状态3。

3、成功了继续按success表转移,直到失败跳转步骤2,或者遇到output表中标明的“可输出状态”(图中红色状态)。此时输出匹配到的模式串,然后将此状态视作普通的状态继续转移。

算法高效之处在于,当自动机接受了“ushe”之后,再接受一个r会导致无法按照success表转移,此时自动机会聪明地按照failure表转移到2号状态,并经过几次转移后输出“hers”。来到2号状态的路不止一条,从根节点一路往下,“h→e”也可以到达。而这个“he”恰好是“ushe”的结尾,状态机就仿佛是压根就没失败过(没有接受r),也没有接受过中间的字符“us”,直接就从初始状态按照“he”的路径走过来一样(到达同一节点,状态完全相同)。

4、代码实现

导入依赖

<dependency>
    <groupId>org.ahocorasick</groupId>
    <artifactId>ahocorasick</artifactId>
    <version>0.4.0</version>
</dependency>
<!-- 工具包  hutool-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.16</version>
</dependency>

新建一个测试类

import cn.hutool.core.util.ObjectUtil;
import org.ahocorasick.trie.Emit;
import org.ahocorasick.trie.Trie;

import java.util.Arrays;
import java.util.Collection;

public class ACTest {

    public static void main(String[] args) {
		// 开始时间
		long stime = System.currentTimeMillis();
		//数据源  大概有1000多个敏感字
		String source = "欢快,欢喜,喜悦,夷愉,愉快,开心,快乐,欢乐,乐意,首肯,愿意,忻悦,欣忭,欣喜,快活,夷悦,怡悦,雀跃,兴奋,欢腾,欢跃,欢欣,欢畅,欢娱,得意,痛快,康乐,安乐,得志,畅快,舒畅,称心,满足,满意欢娱";
		//标签
		String pattern = "喜悦,夷愉,IT学院,快乐,欢腾,欢跃";
		//如果数据源里包含以下标签,就放到result里面
		StringBuilder result = new StringBuilder();
		//通过  ","  来分割数标签放到数组
		String[] words = pattern.split(",");
		// trie  只匹配完整单词
		Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();
		//匹配成功,返回命中的标签
		Collection<Emit> emits = trie.parseText(source);
		// 结束时间
		long etime = System.currentTimeMillis();
		// 计算执行时间
		System.out.printf("执行时长:%d 毫秒", (etime - stime));
		System.out.println();
		System.out.println("命中的标签 :" + emits);
	}
}

运行结果:命中四个标签,运行18ms

执行时长:18 毫秒
命中的标签 :[6:7=喜悦, 9:10=夷愉, 18:19=快乐, 57:58=欢腾, 60:61=欢跃]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值