字符串替换研究
作者:京东零售 周德东
需求非常简单,给定一组关键词,需要将商品名称中出现过的关键字替换掉;
如:skuName="HUAWEI Pura 70 Pro 国家补贴500元 羽砂黑 12GB+512GB 超高速风驰闪拍 华为鸿蒙智能手机" 需要替换成
skuName="HUAWEI Pura 70 Pro 羽砂黑 12GB+512GB 超高速风驰闪拍 华为鸿蒙智能手机" 这里的关键字"国家补贴500元";
直接skuName.replace("国家补贴500元", ""),不就可以了吗?如果是一组,那就循环替换就完了嘛,再考虑到关键字前缀问题,对这一组关键词,按字符长度进行排序,先替换长的关键词,再替换短的就ok了;
如果这一组关键词非常多,上千个怎么办?真实场景也是这样的,一般需要替换的关键词都是比较多,并且使用String.replace上线后,直接CPU打满,基本不可用;
这个字段替换本质上与敏感词过滤是一样的原理,针对敏感词的深入研究,出现了 Aho-Corasick(AC自动机) 算法;
Aho-Corasick(AC自动机)是一种多模式字符串匹配算法,结合了Trie树的前缀匹配能力和KMP算法的失败跳转思想,能够在单次文本扫描中高效匹配多个模式串。其核心优势在于时间复杂度为O(n + m + z)(n为文本长度,m为模式串总长度,z为匹配次数),适用于敏感词过滤、基因序列分析等场景。
二、方案
针对这几种算法进行对比;
字符串替换,定义一个接口,通过4个不同的方案实现,进行性能对比
public interface Replacer {
String replaceKeywords(String text);
}
2.1 String.replace 方案
这种方案最简单,也是关键词少的时候,最有效,最好用的;
public class StrReplacer implements Replacer {
private final List<String> keyWordList;
public StrReplacer(String keyWords) {
this.keyWordList = Lists.newArrayList(keyWords.split(";"));
// 按关键字长度降序排序,确保长关键字优先匹配
keyWordList.sort((a, b) -> Integer.compare(b.length(), a.length()));
}
/**
* 替换文本中所有匹配的关键字为空字符串
*/
@Override
public String replaceKeywords(String text) {
String newTxt = text;
for (String s : keyWordList) {
newTxt = newTxt.replace