您的位置:首页 > 编程语言 > Java开发

简单实现java DFA算法对敏感词过滤

2017-09-27 15:05 615 查看
最近研究了下对敏感词过滤的算法,网上也查了很多资料,自己模仿着写了一个简单的,望批评指教

1、SensitiveFilter类,主要实现添加敏感词和过滤的操作

public class SensitiveFilter {

private static Map<Integer,WorldNode> sensitiveWorld = new HashMap<Integer,WorldNode>();
private static char SIGN = '*';

public static void addSensitiveWorlds(List<String> worlds) {

for(String world:worlds) {
char[] worldCharArray = world.toCharArray();
int convertNum = BCConvert.qj2bj(worldCharArray[0]);
WorldNode senNode = sensitiveWorld.get(convertNum);
//有没有把敏感词首字符放进集合
if(senNode==null) {
senNode = new WorldNode(convertNum, worldCharArray.length==1);
sensitiveWorld.put(convertNum, senNode);
}else {
//设置字符是否为叶子
if(senNode.isLeaf()) {
senNode.setLeaf(worldCharArray.length==1);
}
}
//敏感词子集合
for(int i=1;i<worldCharArray.length;i++) {
boolean flag = i==worldCharArray.length-1;
senNode = senNode.addChildNode(BCConvert.qj2bj(worldCharArray[i]), flag);
}
}
}

public static String doFilter(String source) {
char[] sourceArray = source.toCharArray();
for(int i=0;i<sourceArray.length;i++) {
WorldNode findNode = sensitiveWorld.get(BCConvert.qj2bj(sourceArray[i]));
if(findNode==null) {
continue;
}
int findFlag = i;
boolean senEndMark = false;
//单个过滤字符
if(findNode.isLeaf()) {
senEndMark = true;
}
for(;++findFlag<sourceArray.length;) {
findNode = findNode.queryChildNode(BCConvert.qj2bj(sourceArray[findFlag]));
if(findNode==null) {
break;
}
if(findNode.isLeaf()) {
senEndMark = true;
break;
}
}
if(senEndMark) {
for(int k=i;k<=findFlag;k++) {
sourceArray[k] = SIGN;
}
i=findFlag;
}
}
return new String(sourceArray);
}

public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("天空星星月亮");
list.add("马路");
list.add("哈");
SensitiveFilter.addSensitiveWorlds(list);
System.out.println(JSON.toJSONString(sensitiveWorld));

String doFilterStr = SensitiveFilter.doFilter("在漫天星空下载马路上行走,哈哈");

System.out.println(doFilterStr);

}

}

2、WorldNode类,主要实现添加子集合和查询子集合的功能
public class WorldNode implements Serializable {

private static final long serialVersionUID = 1L;
private int value; //敏感词的值
private List<WorldNode> childNodes; //子敏感词
private boolean isLeaf; //一条敏感词结束标识

public WorldNode(int value, boolean isLeaf) {
this.value = value;
this.isLeaf = isLeaf;
}
public WorldNode() {
}
//添加子集合
public WorldNode addChildNode(int value,boolean isLeaf) {
if(childNodes==null) {
childNodes = new ArrayList<WorldNode>();
}
for(WorldNode worldNode:childNodes) {
if(worldNode.value==value) {
worldNode.setLeaf(isLeaf);
return worldNode;
}
}
WorldNode newNode = new WorldNode(value,isLeaf);
childNodes.add(newNode);
return newNode;
}
//查询子集合
public WorldNode queryChildNode(int value) {
if(childNodes==null) {
return null;
}
for(WorldNode world:childNodes) {
if(world.value==value) {
return world;
}
}
return null;
}

public int getValue() {
return value;
}
public void setValue(int value) {
this.value
4000
= value;
}
public List<WorldNode> getChildNodes() {
return childNodes;
}
public void setChildNodes(List<WorldNode> childNodes) {
this.childNodes = childNodes;
}
public boolean isLeaf() {
return isLeaf;
}
public void setLeaf(boolean isLeaf) {
this.isLeaf = isLeaf;
}

}


3、BCConvert类,这个类是从网上copy的,就是把汉字转化为ASCII码
public class BCConvert {

/**
* ASCII表中可见字符从!开始,偏移位值为33(Decimal)
*/
static final char DBC_CHAR_START = 33; // 半角!

/**
* ASCII表中可见字符到~结束,偏移位值为126(Decimal)
*/
static final char DBC_CHAR_END = 126; // 半角~

/**
* 全角对应于ASCII表的可见字符从!开始,偏移值为65281
*/
static final char SBC_CHAR_START = 65281; // 全角!

/**
* 全角对应于ASCII表的可见字符到~结束,偏移值为65374
*/
static final char SBC_CHAR_END = 65374; // 全角~

/**
* ASCII表中除空格外的可见字符与对应的全角字符的相对偏移
*/
static final int CONVERT_STEP = 65248; // 全角半角转换间隔

/**
* 全角空格的值,它没有遵从与ASCII的相对偏移,必须单独处理
*/
static final char SBC_SPACE = 12288; // 全角空格 12288

/**
* 半角空格的值,在ASCII中为32(Decimal)
*/
static final char DBC_SPACE = ' '; // 半角空格

/**
* <PRE>
* 半角字符->全角字符转换
* 只处理空格,!到˜之间的字符,忽略其他
* </PRE>
*/
private static String bj2qj(String src) {
if (src == null) {
return src;
}
StringBuilder buf = new StringBuilder(src.length());
char[] ca = src.toCharArray();
for (int i = 0; i < ca.length; i++) {
if (ca[i] == DBC_SPACE) { // 如果是半角空格,直接用全角空格替代
buf.append(SBC_SPACE);
} else if ((ca[i] >= DBC_CHAR_START) && (ca[i] <= DBC_CHAR_END)) { // 字符是!到~之间的可见字符
buf.append((char) (ca[i] + CONVERT_STEP));
} else { // 不对空格以及ascii表中其他可见字符之外的字符做任何处理
buf.append(ca[i]);
}
}
return buf.toString();
}

/**
* <PRE>
* 全角字符->半角字符转换
* 只处理全角的空格,全角!到全角~之间的字符,忽略其他
* </PRE>
*/
public static String qj2bj(String src) {
if (src == null) {
return src;
}
StringBuilder buf = new StringBuilder(src.length());
char[] ca = src.toCharArray();
for (int i = 0; i < src.length(); i++) {
if (ca[i] >= SBC_CHAR_START && ca[i] <= SBC_CHAR_END) { // 如果位于全角!到全角~区间内
buf.append((char) (ca[i] - CONVERT_STEP));
} else if (ca[i] == SBC_SPACE) { // 如果是全角空格
buf.append(DBC_SPACE);
} else { // 不处理全角空格,全角!到全角~区间外的字符
buf.append(ca[i]);
}
}
return buf.toString();
}

public static int qj2bj(char src) {
if (src >= SBC_CHAR_START && src <= SBC_CHAR_END) { // 如果位于全角!到全角~区间内
return ((char) (src - CONVERT_STEP));
} else if (src == SBC_SPACE) { // 如果是全角空格
return DBC_SPACE;
} else { // 不处理全角空格,全角!到全角~区间外的字符
return src;
}
}

public static void main(String[] args) {
System.out.println(StringUtils.trimToEmpty(" a,b ,c "));
String s = "nihaohk |   nihehe ,。 78  7 ";
s=BCConvert.qj2bj(s);
System.out.println(s);
System.out.println(BCConvert.bj2qj(s));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息