Java DFA算法实现示例代码

 更新时间:2026年07月18日 09:37:13   作者:Full Stack Developme  
DFA(Deterministic Finite Automaton,确定性有限自动机)是一种常用的算法模型,在Java中广泛应用于、字符串匹配、词法分析等场景,这篇文章给大家介绍Java DFA算法实现示例代码,感兴趣的朋友一起看看吧

DFA(Deterministic Finite Automaton,确定性有限自动机)是一种常用的算法模型,在Java中广泛应用于敏感词过滤、字符串匹配、词法分析等场景。它的核心特点是:每个状态对于同一个输入字符,有且只有一个转移状态

基本原理

DFA算法通过构建一个状态转移图(通常用嵌套Map或数组表示)来快速匹配关键词。相比于简单遍历匹配,时间复杂度为 O(n),n为待匹配文本长度,与关键词数量无关。

Java实现示例

1. 构建DFA节点模型

import java.util.*;
public class DFAFilter {
    // 根节点
    private Map<Character, Object> rootNode = new HashMap<>();
    // 敏感词结束标识
    private static final String END_FLAG = "isEnd";
    /**
     * 添加关键词到DFA中
     * @param keyword 关键词
     */
    public void addKeyword(String keyword) {
        if (keyword == null || keyword.isEmpty()) return;
        Map<Character, Object> currentMap = rootNode;
        for (int i = 0; i < keyword.length(); i++) {
            char c = keyword.charAt(i);
            // 获取下一层节点
            Map<Character, Object> nextMap = 
                (Map<Character, Object>) currentMap.get(c);
            if (nextMap == null) {
                nextMap = new HashMap<>();
                currentMap.put(c, nextMap);
            }
            currentMap = nextMap;
            // 最后一个字符标记结束
            if (i == keyword.length() - 1) {
                currentMap.put(END_FLAG, true);
            }
        }
    }
    /**
     * 批量添加关键词
     */
    public void addKeywords(List<String> keywords) {
        for (String keyword : keywords) {
            addKeyword(keyword);
        }
    }
}

2. 匹配敏感词

/**
 * 检查文本是否包含敏感词,并返回第一个匹配的敏感词
 */
public String check(String text) {
    if (text == null || text.isEmpty()) return null;
    for (int i = 0; i < text.length(); i++) {
        int matchCount = 0;
        Map<Character, Object> currentMap = rootNode;
        char c;
        for (int j = i; j < text.length(); j++) {
            c = text.charAt(j);
            currentMap = (Map<Character, Object>) currentMap.get(c);
            if (currentMap == null) {
                break; // 匹配失败,重新从下一个字符开始
            }
            matchCount++;
            // 检查是否匹配到完整关键词
            if (currentMap.containsKey(END_FLAG)) {
                return text.substring(i, i + matchCount);
            }
        }
    }
    return null;
}
/**
 * 替换文本中的敏感词
 * @param text 原始文本
 * @param replaceChar 替换字符
 * @return 替换后的文本
 */
public String replace(String text, char replaceChar) {
    if (text == null || text.isEmpty()) return text;
    StringBuilder result = new StringBuilder(text);
    List<int[]> positions = new ArrayList<>();
    for (int i = 0; i < text.length(); i++) {
        int matchCount = 0;
        Map<Character, Object> currentMap = rootNode;
        char c;
        for (int j = i; j < text.length(); j++) {
            c = text.charAt(j);
            currentMap = (Map<Character, Object>) currentMap.get(c);
            if (currentMap == null) break;
            matchCount++;
            if (currentMap.containsKey(END_FLAG)) {
                positions.add(new int[]{i, i + matchCount});
                i = i + matchCount - 1; // 跳过已匹配部分
                break;
            }
        }
    }
    // 执行替换
    for (int[] pos : positions) {
        for (int i = pos[0]; i < pos[1]; i++) {
            result.setCharAt(i, replaceChar);
        }
    }
    return result.toString();
}

3. 完整示例

public class DFATest {
    public static void main(String[] args) {
        DFAFilter filter = new DFAFilter();
        // 添加敏感词
        filter.addKeywords(Arrays.asList(
            "色情", "暴力", "赌博", "毒品", "法轮功"
        ));
        // 测试文本
        String text = "这个网站包含色情和暴力内容,还有赌博信息。";
        // 检查敏感词
        String sensitive = filter.check(text);
        System.out.println("检测到敏感词: " + sensitive);
        // 替换敏感词
        String filtered = filter.replace(text, '*');
        System.out.println("过滤后: " + filtered);
    }
}
输出:
检测到敏感词: 色情
过滤后: 这个网站包含**和**内容,还有**信息。

优化版本:支持跳过特殊字符

/**
 * 增强版:支持忽略特殊字符(如空格、标点)
 */
public class AdvancedDFAFilter {
    private Map<Character, Object> rootNode = new HashMap<>();
    private static final String END_FLAG = "isEnd";
    // 忽略字符集合(空格、标点符号等)
    private Set<Character> ignoreChars = new HashSet<>(
        Arrays.asList(' ', ',', '.', '!', '?', ';', ':', '、', ',', '。', '!', '?')
    );
    public void addKeyword(String keyword) {
        Map<Character, Object> currentMap = rootNode;
        for (char c : keyword.toCharArray()) {
            currentMap = (Map<Character, Object>) currentMap.computeIfAbsent(
                c, k -> new HashMap<>()
            );
        }
        currentMap.put(END_FLAG, true);
    }
    public String check(String text) {
        for (int i = 0; i < text.length(); i++) {
            int matchCount = 0;
            Map<Character, Object> currentMap = rootNode;
            for (int j = i; j < text.length(); j++) {
                char c = text.charAt(j);
                // 跳过忽略字符
                if (ignoreChars.contains(c)) {
                    continue;
                }
                currentMap = (Map<Character, Object>) currentMap.get(c);
                if (currentMap == null) break;
                matchCount++;
                if (currentMap.containsKey(END_FLAG)) {
                    return text.substring(i, j + 1);
                }
            }
        }
        return null;
    }
}

性能优化建议

  • 使用数组代替HashMap:当字符集有限(如纯英文)时,可改用Map<Character, Node>Node[] children数组
  • 内存优化:使用char[]int[]手动实现紧凑存储
  • 并行处理:大文本可分片并行匹配
  • 缓存结果:对于重复文本缓存匹配结果

应用场景

  • ✅ 敏感词过滤系统
  • ✅ 垃圾邮件检测
  • ✅ SQL注入检测
  • ✅ 代码语法高亮
  • ✅ 正则表达式引擎底层实现

DFA算法在Java中实现简单、性能优秀,尤其适合需要高性能字符串匹配的场景,相比之下比遍历关键词列表快很多。

到此这篇关于Java DFA算法实现示例代码的文章就介绍到这了,更多相关Java DFA算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解jeefast和Mybatis实现二级联动的问题

    详解jeefast和Mybatis实现二级联动的问题

    这篇文章主要介绍了详解jeefast和Mybatis实现二级联动的问题,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • java 微信随机红包算法代码实例

    java 微信随机红包算法代码实例

    这篇文章主要介绍了java 微信随机红包算法的相关资料,并附实例代码,需要的朋友可以参考下
    2016-10-10
  • Spring中Controller和RestController的区别详解

    Spring中Controller和RestController的区别详解

    这篇文章主要介绍了Spring中Controller和RestController的区别详解,@Controller是标识一个Spring类是Spring MVC controller处理器,@Controller类中的方法可以直接通过返回String跳转到jsp、ftl、html等模版页面,需要的朋友可以参考下
    2023-09-09
  • Java中的Lombok使用及工作原理详解

    Java中的Lombok使用及工作原理详解

    这篇文章主要介绍了Java中的Lombok使用及工作原理详解,Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发,通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量,需要的朋友可以参考下
    2023-10-10
  • Springboot打包为Docker镜像并部署的实现

    Springboot打包为Docker镜像并部署的实现

    这篇文章主要介绍了Springboot打包为Docker镜像并部署的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Java泛型通配符的使用详解

    Java泛型通配符的使用详解

    本文主要介绍了Java泛型通配符的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Springboot多种情况yml配置代码实例

    Springboot多种情况yml配置代码实例

    这篇文章主要介绍了Springboot多种情况yml配置代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • java使用google身份验证器实现动态口令验证的示例

    java使用google身份验证器实现动态口令验证的示例

    本篇文章主要介绍了java使用google身份验证器实现动态口令验证的示例,具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • 使用Java轻松判断一个5位数是否为回文数

    使用Java轻松判断一个5位数是否为回文数

    在编程中,回文数是一个正读和反读都相同的数字,本文将介绍如何使用Java编写一个程序来判断一个5位数是否为回文数,感兴趣的小伙伴可以了解下
    2026-03-03
  • springboot自定义过滤器的方法

    springboot自定义过滤器的方法

    这篇文章主要为大家详细介绍了springboot自定义过滤器的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01

最新评论