C# 屏蔽词过滤
参考:https://www.cnblogs.com/kubidemanong/p/10834993.html
public class TreeNode
{
public char Char;
public bool IsEnd;
public int WordEndAt;
private Dictionary<char, TreeNode> NodeDict;
public TreeNode(char c)
{
Char = c;
IsEnd = false;
NodeDict = new Dictionary<char, TreeNode>();
} public bool ContainChar(char ch)
{
return NodeDict.ContainsKey(ch);
} public TreeNode GetChild(char c)
{
TreeNode Child = null;
NodeDict.TryGetValue(c, out Child);
return Child;
} public TreeNode AddNode(char ch)
{
TreeNode insertNode = null;
if (!NodeDict.TryGetValue(ch, out insertNode))
{
insertNode = new TreeNode(ch);
NodeDict.Add(ch, insertNode);
}
return insertNode;
}
}
public class Trie
{ public TreeNode Root { get; }
private HashSet<char> SkipCharSet; //忽略字符
private HashSet<char> SeparateCharSet; //常见分隔符
private string skipCharList = " `-=[]\\',.·/~!@#$%^&*()_+{}|:\"<>?*\r\n";
private TreeNode checkNode;
private TreeNode backupNode;
private char duplicateChar;
public Trie()
{
Root = new TreeNode(' ');
SkipCharSet = new HashSet<char>();
SeparateCharSet = new HashSet<char>();
foreach (char c in skipCharList)
{
SkipCharSet.Add(c);
SeparateCharSet.Add(c);
}
} public void AddNode(TreeNode node, string word)
{
if (word.Length > 0)
{
char ch = word[0];
TreeNode insertNode = node.AddNode(ch);
if (word.Length == 1)
{
insertNode.IsEnd = true;
}
word = word.Remove(0,1);
AddNode(insertNode, word);
}
} private bool IsSkipChar(char c)
{
return SkipCharSet.Contains(c);
} //是否是英文
private bool IsEnglishChar(char ch)
{
string str = new string(ch, 1);
Regex regEnglish = new Regex("^[a-zA-Z]");
return regEnglish.IsMatch(str);
} //是否是分割符
private bool Separator(char ch)
{
return SeparateCharSet.Contains(ch);
} //是否是单词的开头
private bool IsWordBegin(string word,int pos)
{
if (pos == 0)
return true;
if (pos < word.Length)
{
char c1 = word[pos - 1];
char c2 = word[pos];
return (Separator(c1) && !Separator(c2)) || (!IsEnglishChar(c1) && IsEnglishChar(c2));
}
return false;
} //是否是单词的结尾
private bool IsWordEnd(string word,int pos)
{
if (pos == word.Length - 1)
return true;
if(pos < word.Length)
{
char c1 = word[pos];
char c2 = word[pos + 1];
return (!Separator(c1) && Separator(c2)) || (IsEnglishChar(c1) && !IsEnglishChar(c2));
}
return false;
} private void CheckWord(string checkWord,int begin)
{
int index = begin;
while(index + 1 < checkWord.Length)
{
++index;
char ch = checkWord[index];
if (IsSkipChar(ch))
{
if (checkNode.ContainChar(ch))
checkNode = checkNode.GetChild(ch);
}
else
{
if(checkNode.ContainChar(ch))
{
checkNode = checkNode.GetChild(ch);
if(checkNode.IsEnd)
{
checkNode.WordEndAt = index;
backupNode = checkNode;
duplicateChar = ch;
CheckWord(checkWord,index); //继续匹配
break;
}
}
else
{
if (duplicateChar == ch) //屏蔽fuccccccck例如这样的
backupNode.WordEndAt = index;
else
break;
}
}
duplicateChar = ch;
}
} public string Filter(string filterWord)
{
int begin = 0;
checkNode = null;
backupNode = null;
duplicateChar = ' ';
string word = filterWord.ToLower();
StringBuilder result = new StringBuilder(filterWord);
while(begin < word.Length)
{
checkNode = Root;
backupNode = Root;
char ch = word[begin];
duplicateChar = ch;
//设置是否严格匹配, 即逐个字符检测是否有可能是敏感词,否则像英语一样只检测单词,
//严格匹配: [av]是敏感词,那么[avoid]被替换成[**oid]
bool isStrict = !IsEnglishChar(ch);
bool isWordBegin = isStrict || IsWordBegin(word, begin);
if(isWordBegin && checkNode.ContainChar(ch))
{
checkNode = checkNode.GetChild(ch);
if(!IsSkipChar(ch))
{
CheckWord(word, begin);
if(backupNode.IsEnd && backupNode.WordEndAt > 0)
{
bool isWordEnd = isStrict || IsWordEnd(word, backupNode.WordEndAt); //到单词末尾才行 have 中有av 但是不是末尾 所以不是屏蔽词
if(isWordEnd)
{
for(int i = begin; i <= backupNode.WordEndAt;++i)
{
result[i] = '*';
}
begin = backupNode.WordEndAt;
}
}
}
}
++begin;
} return result.ToString();
}
}
测试用例:
class Program
{
static void Main(string[] args)
{
Trie trie = new Trie();
trie.AddNode(trie.Root, "fuc");
trie.AddNode(trie.Root, "fuc bitch");
trie.AddNode(trie.Root, "fuck");
trie.AddNode(trie.Root, "bitch");
trie.AddNode(trie.Root, "屠杀");
Console.WriteLine(trie.Filter("是哦fuckkkkkk山大的撒bi\tch"));
Console.WriteLine(trie.Filter("have world fuc bitch"));
Console.WriteLine(trie.Filter("1218fuck1")); Console.ReadKey();
}
}
结果:
C# 屏蔽词过滤的更多相关文章
- Java实现敏感词过滤 - IKAnalyzer中文分词工具
IKAnalyzer 是一个开源的,基于java语言开发的轻量级的中文分词工具包. 官网: https://code.google.com/archive/p/ik-analyzer/ 本用例借助 I ...
- Java实现敏感词过滤 - DFA算法
Java实现DFA算法进行敏感词过滤 封装工具类如下: 使用前需对敏感词库进行初始化: SensitiveWordUtil.init(sensitiveWordSet); package cn.swf ...
- [原创] Trie树 php 实现敏感词过滤
目录 背景 简介 存储结构 PHP 其他语言 字符串分割 示例代码 php 优化 缓存字典树 常驻服务 参考文章 背景 项目中需要过滤用户发送的聊天文本, 由于敏感词有将近2W条, 如果用 str_r ...
- [python每日一练]--0012:敏感词过滤 type2
题目链接:https://github.com/Show-Me-the-Code/show-me-the-code代码github链接:https://github.com/wjsaya/python ...
- java实现敏感词过滤(DFA算法)
小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解. 敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxo ...
- 用php实现一个敏感词过滤功能
周末空余时间撸了一个敏感词过滤功能,下边记录下实现过程. 敏感词,一方面是你懂的,另一方面是我们自己可能也要过滤一些人身攻击或者广告信息等,具体词库可以google下,有很多. 过滤敏感词,使用简单的 ...
- 浅析敏感词过滤算法(C++)
为了提高查找效率,这里将敏感词用树形结构存储,每个节点有一个map成员,其映射关系为一个string对应一个TreeNode. STL::map是按照operator<比较判断元素是否相同,以及 ...
- Java实现敏感词过滤
敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...
- php敏感词过滤
在项目开发中发现有个同事在做敏感词过滤的时候用循环在判断,其实是不用这样做的,用php的数组函数和字符串函数即可实现 function filterNGWords($string) { $badwor ...
- 转:鏖战双十一-阿里直播平台面临的技术挑战(webSocket, 敏感词过滤等很不错)
转自:http://www.infoq.com/cn/articles/alibaba-broadcast-platform-technology-challenges 鏖战双十一-阿里直播平台面临的 ...
随机推荐
- 一、100ASK_IMX6ULL嵌入式裸板学习_LED实验(中)
以C语言方式驱动(例程与代码分析) 韦东山的例程: start.s部分: .text .global _start @全局标号 _start: //设置栈 ldr sp,=0x80200000 @设置 ...
- windows下搭建stm8s开发环境
拓扑:windows -> st_link_v2 ->目标板,目标板不由st_link_v2供电 接线: st_link_v2: NRST GND SWIM 3V3 ↓ ↓ ↓ ↓ 目标板 ...
- idea等工具网盘下载地址
1.idea2020 下载地址:https://caiyun.139.com/m/i?1E5C2SkIZbJH4 ,下载密码微信 搜索 "白菜拼吧" 回复 idea2020 获取 ...
- ts language service
- IC杂记
BNF(Backus-Naur Form) 巴科斯范式, 以美国人巴科斯(Backus)和丹麦人诺尔(Naur)的名字命名的一种形式化的语法表示方法,用来描述语法的一种形式体系,是一种典型的元语言.又 ...
- KingbaseES V8R6备份恢复案例之---自定义表空间指定恢复目录数据恢复
案例说明: KingbaseES V8R6在通过sys_rman执行物理备份恢复时,可以通过参数'--kb1-path',指定恢复的数据(data)目录,但如果原备份中包含自定义表空间时,需要建立表空 ...
- vue动态切换图片
1.踩的一个坑是:直接获取对象,使用style改变其背景图地址或者对img标签改变src值 因为经过vue经过打包编译后,图片地址已经被处理了,这时更新地址是无效的,会找不到图片. 所以可以用多个标签 ...
- GoLang之ACM控制台输入输出
转自:https://blog.csdn.net/weixin_52690231/article/details/125436414
- MyBatis_04(MyBatis获取“参数值”的两种方式)
MyBatis获取"参数值"的两种方式 (重点!!!) MyBatis获取参数值的两种方式:${}和#{} ${}的本质就是字符串拼接 , #{}的本质就是占位符赋值 ${}使用字 ...
- groupByKey、reduceByKey、aggregateByKey、foldByKey、combineByKey的联系和区别
groupByKey根据key对value进行分组,默认没有预聚合 combineByKeyWithClassTag[CompactBuffer[V]]( createCombiner, mergeV ...