A palavra sensível é uma ferramenta de palavras sensíveis a alto desempenho baseada no algoritmo DFA.
Experiência online
Se você tem algumas doenças difíceis e complicadas, pode participar: grupo de troca técnica
Sensível-Word-Admin é o aplicativo de console correspondente. As funções estão atualmente nos estágios iniciais do desenvolvimento e a versão MVP está disponível.
Olá a todos, eu sou Lao Ma.
Eu sempre quis implementar uma ferramenta de palavras sensíveis simples e fácil de usar, então implementei essa ferramenta de código aberto.
Com base na implementação do algoritmo DFA, o conteúdo do sinário sensível atualmente inclui 6W+ (arquivo de origem 18W+, após uma exclusão).
No estágio posterior, o dicionário sensível será otimizado e suplementado continuamente, e o desempenho do algoritmo será melhorado ainda mais.
A v0.24.0 começou a apoiar a classificação e o refinamento de palavras sensíveis, mas a carga de trabalho é relativamente grande, portanto, há inevitavelmente omissões.
Bem -vindo às melhorias de relações públicas, solicitações do GitHub ou ingressar no grupo de intercâmbio técnico para se comunicar e se gabar!
6W+ Thesaurus, e otimização e atualização contínuas
Com base na implementação de API fluente, o uso elegante e conciso
Com base no algoritmo DFA, o desempenho é 7W+ QPS, o aplicativo é insensível
Apoiar operações comuns, como julgamento, retorno e dessensibilização de palavras sensíveis
Suporta conversão de formato comum
Intercâmbio de meia largura de largura total, intercâmbio de casos em inglês, formas comuns de números, chinês tradicional e chinês simplificado, formas comuns de intercâmbio inglês, ignorando palavras duplicadas, etc.
Suporte a detecção de palavras sensíveis, detecção de email, detecção digital, detecção de sites, IPv4, etc.
Suporta políticas de substituição personalizadas
Suporta palavras sensíveis e permutas definidas pelo usuário
Suporta atualizações dinâmicas de dados (personalização do usuário), efetivas em tempo real
Suporta interface de tag + implementação de classificação interna para palavras sensíveis
Suporte a pular alguns personagens especiais para tornar a correspondência mais flexível
Suporta adição/modificação única de listas em preto e branco, sem inicialização completa
Change_log.md
Às vezes, existe um console para palavras sensíveis, o que torna mais flexível e conveniente para configurar.
Como implementar o Serviço Sensível do Console de Words do Word?
Um grande número de arquivos sensíveis de tag word foram resolvidos, o que pode tornar nossas palavras sensíveis mais convenientes.
Esses dois materiais podem ser lidos no artigo abaixo:
V0.11.0 Recursos-novos de palavras sensíveis e arquivos de tag correspondentes
Atualmente, a v0.24.0 possui tags de palavras embutidas e é recomendável atualizar para a versão mais recente, se necessário.
O código aberto não é fácil. Se este projeto for útil para você, você pode convidar Lao Ma a tomar uma xícara de chá de leite.

JDK1.8+
Maven 3.x+
< dependency >
< groupId >com.github.houbb</ groupId >
< artifactId >sensitive-word</ artifactId >
< version >0.24.0</ version >
</ dependency > SensitiveWordHelper é uma classe de ferramentas para palavras sensíveis. Os métodos principais são os seguintes:
NOTA: SensitiveWordHelper fornece configurações padrão. Se você deseja fazer configurações personalizadas flexíveis, consulte a configuração do recurso de classe de inicialização
| método | parâmetro | Valor de retorno | ilustrar |
|---|---|---|---|
| contém (string) | A string a ser verificada | Valor booleano | Verifique se a string contém palavras sensíveis |
| Substitua (string, isensitivewordreplace) | Substitua palavras sensíveis por estratégia de substituição especificada | Corda | Retorna a corda dessensibilizada |
| Substitua (string, char) | Use o char especificado para substituir a palavra sensível | Corda | Retorna a corda dessensibilizada |
| Substitua (string) | Use * para substituir palavras sensíveis | Corda | Retorna a corda dessensibilizada |
| Findall (string) | A string a ser verificada | Lista de strings | Retorna todas as palavras sensíveis na string |
| Findfirst (String) | A string a ser verificada | Corda | Retorna a primeira palavra sensível na string |
| Findall (string, iWordResultHandler) | INWORDRESULTHandler Resultado Classe de processamento | Lista de strings | Retorna todas as palavras sensíveis na string |
| Findfirst (String, iWordResultHandler) | INWORDRESULTHandler Resultado Classe de processamento | Corda | Retorna a primeira palavra sensível na string |
| tags (string) | Obtenha tags para palavras sensíveis | String de palavra sensível | Retorne à lista de tags para palavras sensíveis |
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( SensitiveWordHelper . contains ( text )); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
String word = SensitiveWordHelper . findFirst ( text );
Assert . assertEquals ( "五星红旗" , word );SensívelwordHelper.findfirst (texto) é equivalente a:
String word = SensitiveWordHelper . findFirst ( text , WordResultHandlers . word ()); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
List < String > wordList = SensitiveWordHelper . findAll ( text );
Assert . assertEquals ( "[五星红旗, 毛主席, 天安门]" , wordList . toString ());Retorna todo o uso de palavras sensíveis é semelhante ao SensiveWordHelper.findfirst () e também suporta especificar classes de processamento de resultados.
SensívelwordHelper.findall (texto) é equivalente a:
List < String > wordList = SensitiveWordHelper . findAll ( text , WordResultHandlers . word ());WordresultHandlers.raw () pode manter as informações correspondentes do subscrito e as informações da categoria:
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
// 默认敏感词标签为空
List < WordTagsDto > wordList1 = SensitiveWordHelper . findAll ( text , WordResultHandlers . wordTags ());
Assert . assertEquals ( "[WordTagsDto{word='五星红旗', tags=[]}, WordTagsDto{word='毛主席', tags=[]}, WordTagsDto{word='天安门', tags=[]}]" , wordList1 . toString ()); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
String result = SensitiveWordHelper . replace ( text );
Assert . assertEquals ( "****迎风飘扬,***的画像屹立在***前。" , result ); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
String result = SensitiveWordHelper . replace ( text , '0' );
Assert . assertEquals ( "0000迎风飘扬,000的画像屹立在000前。" , result );V0.2.0 suporta esse recurso.
Descrição da cena: Às vezes, queremos que diferentes palavras sensíveis tenham diferentes resultados de substituição. Por exemplo, [o jogo] é substituído por [e-sports] e [desemprego] é substituído por [emprego flexível].
É certo que não há problema em usar a substituição regular de strings com antecedência, mas o desempenho é média.
Exemplo de uso:
/**
* 自定替换策略
* @since 0.2.0
*/
@ Test
public void defineReplaceTest () {
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
ISensitiveWordReplace replace = new MySensitiveWordReplace ();
String result = SensitiveWordHelper . replace ( text , replace );
Assert . assertEquals ( "国家旗帜迎风飘扬,教员的画像屹立在***前。" , result );
} Entre eles, MySensitiveWordReplace está nossa política de substituição personalizada, que é implementada da seguinte maneira:
public class MyWordReplace implements IWordReplace {
@ Override
public void replace ( StringBuilder stringBuilder , final char [] rawChars , IWordResult wordResult , IWordContext wordContext ) {
String sensitiveWord = InnerWordCharUtils . getString ( rawChars , wordResult );
// 自定义不同的敏感词替换策略,可以从数据库等地方读取
if ( "五星红旗" . equals ( sensitiveWord )) {
stringBuilder . append ( "国家旗帜" );
} else if ( "毛主席" . equals ( sensitiveWord )) {
stringBuilder . append ( "教员" );
} else {
// 其他默认使用 * 代替
int wordLength = wordResult . endIndex () - wordResult . startIndex ();
for ( int i = 0 ; i < wordLength ; i ++) {
stringBuilder . append ( '*' );
}
}
}
} Fazemos mapeamento corrigido para algumas das palavras e as outras são convertidas para * por padrão.
O iWordResultHandler pode processar resultados de palavras sensíveis e permitir que os usuários os personalizem.
Veja a classe de ferramentas WordResultHandlers para implementação interna:
Apenas palavras sensíveis são preservadas.
Retire informações relacionadas a palavras sensíveis, incluindo os subscritos iniciais e finais de palavras sensíveis.
Ao mesmo tempo, as palavras e as informações correspondentes do rótulo da palavra são retidas.
Consulte SensitiveWordHelPerTest para todos os casos de teste
1) Exemplos básicos
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
List < String > wordList = SensitiveWordHelper . findAll ( text );
Assert . assertEquals ( "[五星红旗, 毛主席, 天安门]" , wordList . toString ());
List < String > wordList2 = SensitiveWordHelper . findAll ( text , WordResultHandlers . word ());
Assert . assertEquals ( "[五星红旗, 毛主席, 天安门]" , wordList2 . toString ());
List < IWordResult > wordList3 = SensitiveWordHelper . findAll ( text , WordResultHandlers . raw ());
Assert . assertEquals ( "[WordResult{startIndex=0, endIndex=4}, WordResult{startIndex=9, endIndex=12}, WordResult{startIndex=18, endIndex=21}]" , wordList3 . toString ()); Especificamos as informações da tag da palavra correspondente no arquivo dict_tag_test.txt .
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
// 默认敏感词标签为空
List < WordTagsDto > wordList1 = SensitiveWordHelper . findAll ( text , WordResultHandlers . wordTags ());
Assert . assertEquals ( "[WordTagsDto{word='五星红旗', tags=[]}, WordTagsDto{word='毛主席', tags=[]}, WordTagsDto{word='天安门', tags=[]}]" , wordList1 . toString ());
List < WordTagsDto > wordList2 = SensitiveWordBs . newInstance ()
. wordTag ( WordTags . file ( "dict_tag_test.txt" ))
. init ()
. findAll ( text , WordResultHandlers . wordTags ());
Assert . assertEquals ( "[WordTagsDto{word='五星红旗', tags=[政治, 国家]}, WordTagsDto{word='毛主席', tags=[政治, 伟人, 国家]}, WordTagsDto{word='天安门', tags=[政治, 国家, 地址]}]" , wordList2 . toString ());Os recursos subsequentes são direcionados principalmente a vários processos direcionados a várias situações, de modo a melhorar a taxa de acerto de palavras sensíveis o máximo possível.
Esta é uma longa batalha de ofensa e defesa.
final String text = "fuCK the bad words." ;
String word = SensitiveWordHelper . findFirst ( text );
Assert . assertEquals ( "fuCK" , word ); final String text = "fuck the bad words." ;
String word = SensitiveWordHelper . findFirst ( text );
Assert . assertEquals ( "fuck" , word );Aqui, a conversão de formas comuns de digital é implementada.
final String text = "这个是我的微信:9⓿二肆⁹₈③⑸⒋➃㈤㊄" ;
List < String > wordList = SensitiveWordBs . newInstance (). enableNumCheck ( true ). init (). findAll ( text );
Assert . assertEquals ( "[9⓿二肆⁹₈③⑸⒋➃㈤㊄]" , wordList . toString ()); final String text = "我爱我的祖国和五星紅旗。" ;
List < String > wordList = SensitiveWordHelper . findAll ( text );
Assert . assertEquals ( "[五星紅旗]" , wordList . toString ()); final String text = "Ⓕⓤc⒦ the bad words" ;
List < String > wordList = SensitiveWordHelper . findAll ( text );
Assert . assertEquals ( "[Ⓕⓤc⒦]" , wordList . toString ()); final String text = "ⒻⒻⒻfⓤuⓤ⒰cⓒ⒦ the bad words" ;
List < String > wordList = SensitiveWordBs . newInstance ()
. ignoreRepeat ( true )
. init ()
. findAll ( text );
Assert . assertEquals ( "[ⒻⒻⒻfⓤuⓤ⒰cⓒ⒦]" , wordList . toString ());Informações pessoais como endereço de email não estão ativadas por padrão.
final String text = "楼主好人,邮箱 [email protected]" ;
List < String > wordList = SensitiveWordBs . newInstance (). enableEmailCheck ( true ). init (). findAll ( text );
Assert . assertEquals ( "[[email protected]]" , wordList . toString ());Geralmente é usado para filtrar informações de publicidade, como número de telefone celular/QQ, e não é ativado por padrão.
Após a v0.2.1, os comprimentos detectados por numCheckLen(长度) são suportados.
final String text = "你懂得:12345678" ;
// 默认检测 8 位
List < String > wordList = SensitiveWordBs . newInstance ()
. enableNumCheck ( true )
. init (). findAll ( text );
Assert . assertEquals ( "[12345678]" , wordList . toString ());
// 指定数字的长度,避免误杀
List < String > wordList2 = SensitiveWordBs . newInstance ()
. enableNumCheck ( true )
. numCheckLen ( 9 )
. init ()
. findAll ( text );
Assert . assertEquals ( "[]" , wordList2 . toString ());Usado para filtrar informações comuns de URL, não ativado por padrão.
v0.18.0 otimiza a detecção de URL, que é mais rigorosa e reduz a taxa de julgamento
final String text = "点击链接 https://www.baidu.com 查看答案" ;
final SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance (). enableUrlCheck ( true ). init ();
List < String > wordList = sensitiveWordBs . findAll ( text );
Assert . assertEquals ( "[https://www.baidu.com]" , wordList . toString ());
Assert . assertEquals ( "点击链接 ********************* 查看答案" , sensitiveWordBs . replace ( text ));V0.17.0 Suporte
Evite usuários ignorando a detecção de URL por meio de IP, etc., que não está ativado por padrão.
final String text = "个人网站,如果网址打不开可以访问 127.0.0.1。" ;
final SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance (). enableIpv4Check ( true ). init ();
List < String > wordList = sensitiveWordBs . findAll ( text );
Assert . assertEquals ( "[127.0.0.1]" , wordList . toString ());Os recursos acima são todos ativados por padrão e, às vezes, a empresa precisa definir com flexibilidade os recursos de configuração relacionados.
Então, v0.0.14 abre a configuração da propriedade.
Para fazer uso mais elegante, a definição é usada uniformemente pelo fluente-api.
Os usuários podem usar SensitiveWordBs para defini -lo da seguinte forma:
NOTA: Após a configuração, use nosso objeto SensitiveWordBs recém -definido em vez do método de ferramenta anterior. A configuração do método da ferramenta é tudo padrão.
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. ignoreCase ( true )
. ignoreWidth ( true )
. ignoreNumStyle ( true )
. ignoreChineseStyle ( true )
. ignoreEnglishStyle ( true )
. ignoreRepeat ( false )
. enableNumCheck ( false )
. enableEmailCheck ( false )
. enableUrlCheck ( false )
. enableIpv4Check ( false )
. enableWordCheck ( true )
. numCheckLen ( 8 )
. wordTag ( WordTags . none ())
. charIgnore ( SensitiveWordCharIgnores . defaults ())
. wordResultCondition ( WordResultConditions . alwaysTrue ())
. init ();
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( wordBs . contains ( text ));A descrição de cada configuração é a seguinte:
| Número de série | método | ilustrar | valor padrão |
|---|---|---|---|
| 1 | ignorecase | Ignorar o caso | verdadeiro |
| 2 | ignorewidth | Ignore os cantos arredondados de meio canto | verdadeiro |
| 3 | Ignorenumstyle | Ignore a escrita de números | verdadeiro |
| 4 | ignore Chinesstyle | Ignore o formato de escrita chinesa | verdadeiro |
| 5 | ignoreenglishstyle | Ignorar o formato de escrita em inglês | verdadeiro |
| 6 | ignoreepeat | Ignore palavras duplicadas | falso |
| 7 | EnablenumCheck | Se deve habilitar a detecção digital. | falso |
| 8 | HabilableMailCheck | A detecção de email está ativada | falso |
| 9 | enableurlcheck | Se deve habilitar a detecção de link | falso |
| 10 | enableipv4check | Se deve habilitar a detecção de IPv4 | falso |
| 11 | enablewordcheck | Se deve ativar a detecção de palavras sensíveis | verdadeiro |
| 12 | Numchecklen | Detecção digital, personalize o comprimento especificado. | 8 |
| 13 | WordTag | As tags correspondentes das palavras | nenhum |
| 14 | Charignore | Personagens ignorados | nenhum |
| 15 | WordresultCondition | Processamento adicional para combinar palavras sensíveis, como limitar a necessidade de correspondências completas de palavras em inglês | Sempre verdadeiro |
v0.16.1 é suportado. Às vezes, precisamos liberar a memória, que pode ser a seguinte:
Sobre problemas de reciclagem de memória
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. init ();
// 后续因为一些原因移除了对应信息,希望释放内存。
wordBs . destroy ();Cenário de uso: Após a inicialização, queremos adicionar/excluir uma única palavra em vez de reinicializá -la completamente. Esse recurso é preparado para isso.
Versão suportada: v0.19.0
addWord(word) adiciona palavras sensíveis, apoiando palavras/coleções únicas
removeWord(word) remove palavras sensíveis, suporta palavras/coleções únicas
final String text = "测试一下新增敏感词,验证一下删除和新增对不对" ;
SensitiveWordBs sensitiveWordBs =
SensitiveWordBs . newInstance ()
. wordAllow ( WordAllows . empty ())
. wordDeny ( WordDenys . empty ())
. init ();
// 当前
Assert . assertEquals ( "[]" , sensitiveWordBs . findAll ( text ). toString ());
// 新增单个
sensitiveWordBs . addWord ( "测试" );
sensitiveWordBs . addWord ( "新增" );
Assert . assertEquals ( "[测试, 新增, 新增]" , sensitiveWordBs . findAll ( text ). toString ());
// 删除单个
sensitiveWordBs . removeWord ( "新增" );
Assert . assertEquals ( "[测试]" , sensitiveWordBs . findAll ( text ). toString ());
sensitiveWordBs . removeWord ( "测试" );
Assert . assertEquals ( "[]" , sensitiveWordBs . findAll ( text ). toString ());
// 新增集合
sensitiveWordBs . addWord ( Arrays . asList ( "新增" , "测试" ));
Assert . assertEquals ( "[测试, 新增, 新增]" , sensitiveWordBs . findAll ( text ). toString ());
// 删除集合
sensitiveWordBs . removeWord ( Arrays . asList ( "新增" , "测试" ));
Assert . assertEquals ( "[]" , sensitiveWordBs . findAll ( text ). toString ());
// 新增数组
sensitiveWordBs . addWord ( "新增" , "测试" );
Assert . assertEquals ( "[测试, 新增, 新增]" , sensitiveWordBs . findAll ( text ). toString ());
// 删除集合
sensitiveWordBs . removeWord ( "新增" , "测试" );
Assert . assertEquals ( "[]" , sensitiveWordBs . findAll ( text ). toString ());Cenário de uso: Após a inicialização, queremos adicionar/excluir uma única palavra em vez de reinicializá -la completamente. Esse recurso é preparado para isso.
Versão suportada: v0.21.0
addWordAllow(word) adiciona uma nova lista de permissões, suporta palavras/coleções únicas
removeWordAllow(word) remove as permissões de permissões, suporta palavras/coleções únicas
final String text = "测试一下新增敏感词白名单,验证一下删除和新增对不对" ;
SensitiveWordBs sensitiveWordBs =
SensitiveWordBs . newInstance ()
. wordAllow ( WordAllows . empty ())
. wordDeny ( new IWordDeny () {
@ Override
public List < String > deny () {
return Arrays . asList ( "测试" , "新增" );
}
})
. init ();
// 当前
Assert . assertEquals ( "[测试, 新增, 新增]" , sensitiveWordBs . findAll ( text ). toString ());
// 新增单个
sensitiveWordBs . addWordAllow ( "测试" );
sensitiveWordBs . addWordAllow ( "新增" );
Assert . assertEquals ( "[]" , sensitiveWordBs . findAll ( text ). toString ());
// 删除单个
sensitiveWordBs . removeWordAllow ( "测试" );
Assert . assertEquals ( "[测试]" , sensitiveWordBs . findAll ( text ). toString ());
sensitiveWordBs . removeWordAllow ( "新增" );
Assert . assertEquals ( "[测试, 新增, 新增]" , sensitiveWordBs . findAll ( text ). toString ());
// 新增集合
sensitiveWordBs . addWordAllow ( Arrays . asList ( "新增" , "测试" ));
Assert . assertEquals ( "[]" , sensitiveWordBs . findAll ( text ). toString ());
// 删除集合
sensitiveWordBs . removeWordAllow ( Arrays . asList ( "新增" , "测试" ));
Assert . assertEquals ( "[测试, 新增, 新增]" , sensitiveWordBs . findAll ( text ). toString ());
// 新增数组
sensitiveWordBs . addWordAllow ( "新增" , "测试" );
Assert . assertEquals ( "[]" , sensitiveWordBs . findAll ( text ). toString ());
// 删除集合
sensitiveWordBs . removeWordAllow ( "新增" , "测试" );
Assert . assertEquals ( "[测试, 新增, 新增]" , sensitiveWordBs . findAll ( text ). toString ());Este método é abandonado . Recomenda -se usar o método de adição incremental acima para evitar carregamento total. Para compatibilidade, esse método permanece.
Como usar: Ao chamar sensitiveWordBs.init() , reconstrua o vocabulário sensível com base no iworddeny+iDordallow. Como a inicialização pode levar muito tempo (segundo nível), todas as otimizações para init não afetarão a função antiga do vocabulário quando não for concluída, e a nova prevalecerá após a conclusão .
@ Component
public class SensitiveWordService {
@ Autowired
private SensitiveWordBs sensitiveWordBs ;
/**
* 更新词库
*
* 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法。
* 如果需要生效,则调用这个方法。
*
* 说明:重新初始化不影响旧的方法使用。初始化完成后,会以新的为准。
*/
public void refresh () {
// 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法,然后调用这个方法。
sensitiveWordBs . init ();
}
} Como mencionado acima, você pode acionar ativamente a inicialização do sensitiveWordBs.init(); Quando o léxico do banco de dados muda e o banco de dados precisa entrar em vigor.
Outros usos permanecem os mesmos sem reiniciar o aplicativo.
Versão suportada: v0.13.0
Às vezes, podemos querer limitar ainda mais as palavras confidenciais correspondentes, por exemplo, embora definamos [AV] como uma palavra sensível, não queremos que [tenhamos] sejam correspondidos.
Você pode personalizar a interface WordResultCondition e implementar suas próprias políticas.
A política integrada em WordResultConditions#alwaysTrue() é sempre verdadeira, enquanto WordResultConditions#englishWordMatch() exige que o idioma inglês seja correspondente à palavra completa.
A classe de ferramentas WordresultConditions pode obter políticas correspondentes
| concluir | ilustrar | Versão suportada |
|---|---|---|
| sempre em verdade | Sempre verdadeiro | |
| EnglishWordMatch | Palavra em inglês Combando a palavra completa | v0.13.0 |
| EnglishWordNummatch | Palavra/número de inglês em inglês correspondência completa | v0.20.0 |
| WordTags | Aqueles que satisfazem tags específicas, como focar apenas nas tags [publicidade] | v0.23.0 |
| Correntes (IwordResultCondition ... Condições) | Suporta especificar várias condições e satisfazê -las ao mesmo tempo | v0.23.0 |
Situação padrão original:
final String text = "I have a nice day。" ;
List < String > wordList = SensitiveWordBs . newInstance ()
. wordDeny ( new IWordDeny () {
@ Override
public List < String > deny () {
return Collections . singletonList ( "av" );
}
})
. wordResultCondition ( WordResultConditions . alwaysTrue ())
. init ()
. findAll ( text );
Assert . assertEquals ( "[av]" , wordList . toString ());Podemos especificar que o inglês deve corresponder à palavra completa.
final String text = "I have a nice day。" ;
List < String > wordList = SensitiveWordBs . newInstance ()
. wordDeny ( new IWordDeny () {
@ Override
public List < String > deny () {
return Collections . singletonList ( "av" );
}
})
. wordResultCondition ( WordResultConditions . englishWordMatch ())
. init ()
. findAll ( text );
Assert . assertEquals ( "[]" , wordList . toString ());Obviamente, estratégias mais complexas podem ser implementadas conforme necessário.
Versão suportada: v0.23.0
Só podemos retornar palavras sensíveis afiliadas a um certo rótulo.
Especificamos duas palavras sensíveis: produto, AV
MyWordTag é uma implementação sensível de tag word que definimos:
/**
* 自定义单词标签
* @since 0.23.0
*/
public class MyWordTag extends AbstractWordTag {
private static Map < String , Set < String >> dataMap ;
static {
dataMap = new HashMap <>();
dataMap . put ( "商品" , buildSet ( "广告" , "中文" ));
dataMap . put ( "AV" , buildSet ( "色情" , "单词" , "英文" ));
}
private static Set < String > buildSet ( String ... tags ) {
Set < String > set = new HashSet <>();
for ( String tag : tags ) {
set . add ( tag );
}
return set ;
}
@ Override
protected Set < String > doGetTag ( String word ) {
return dataMap . get ( word );
}
}Por exemplo, simulamos duas classes de implementação diferentes, cada uma focando em uma tag de palavra diferente.
// 只关心SE情
SensitiveWordBs sensitiveWordBsYellow = SensitiveWordBs . newInstance ()
. wordDeny ( new IWordDeny () {
@ Override
public List < String > deny () {
return Arrays . asList ( "商品" , "AV" );
}
})
. wordAllow ( WordAllows . empty ())
. wordTag ( new MyWordTag ())
. wordResultCondition ( WordResultConditions . wordTags ( Arrays . asList ( "色情" )))
. init ();
// 只关心广告
SensitiveWordBs sensitiveWordBsAd = SensitiveWordBs . newInstance ()
. wordDeny ( new IWordDeny () {
@ Override
public List < String > deny () {
return Arrays . asList ( "商品" , "AV" );
}
})
. wordAllow ( WordAllows . empty ())
. wordTag ( new MyWordTag ())
. wordResultCondition ( WordResultConditions . wordTags ( Arrays . asList ( "广告" )))
. init ();
final String text = "这些 AV 商品什么价格?" ;
Assert . assertEquals ( "[AV]" , sensitiveWordBsYellow . findAll ( text ). toString ());
Assert . assertEquals ( "[商品]" , sensitiveWordBsAd . findAll ( text ). toString ());Nossas palavras sensíveis são geralmente mais contínuas, como [chapéu bobo]
Depois, há uma descoberta inteligente de que você pode adicionar alguns personagens no meio, como [bobo! @#$ Hat] Para pular a detecção, mas o poder de ataque do juramento não é reduzido.
Então, como lidar com esses cenários semelhantes?
Podemos especificar conjuntos de skip de caracteres especiais e ignorar esses caracteres sem sentido.
v0.11.0 inicia o suporte
A estratégia de caracteres correspondente a Charignore pode ser definida com flexibilidade pelos usuários.
final String text = "傻@冒,狗+东西" ;
//默认因为有特殊字符分割,无法识别
List < String > wordList = SensitiveWordBs . newInstance (). init (). findAll ( text );
Assert . assertEquals ( "[]" , wordList . toString ());
// 指定忽略的字符策略,可自行实现。
List < String > wordList2 = SensitiveWordBs . newInstance ()
. charIgnore ( SensitiveWordCharIgnores . specialChars ())
. init ()
. findAll ( text );
Assert . assertEquals ( "[傻@冒, 狗+东西]" , wordList2 . toString ());Às vezes, queremos adicionar um rótulo classificado a palavras sensíveis: como situação social, violência etc.
Dessa forma, mais características podem ser executadas de acordo com os rótulos, etc., como apenas processar um certo tipo de etiqueta.
Versão suportada: v0.10.0
Recursos principais Versão de suporte: v0.24.0
Esta é apenas uma interface abstrata, e os usuários podem definir a implementação por si mesmos. Por exemplo, da consulta de banco de dados, leitura de arquivos, chamadas de API etc.
public interface IWordTag {
/**
* 查询标签列表
* @param word 脏词
* @return 结果
*/
Set < String > getTag ( String word );
} Para facilitar o uso na maioria das situações, algumas estratégias de cenas são implementadas na classe WordTags
| Método de implementação | ilustrar | Observação |
|---|---|---|
| nenhum() | Implementação vazia | V0.10.0 Suporte |
| arquivo (string filepath) | Especifique o caminho do arquivo | V0.10.0 Suporte |
| arquivo (string filepath, string wordsplit, string tagsplit) | Especifique caminhos de arquivo, bem como separadores de palavras e separadores de tags | V0.10.0 Suporte |
| mapa (mapa final <string, set> wordtagmap) | Inicialização de acordo com o mapa | V0.24.0 Suporte |
| linhas (linhas de coleta) | Lista de strings | V0.24.0 Suporte |
| Linhas (linhas de coleta, string wordsplit, string tagspli) | Lista de cordas, bem como separadores de palavras e separadores de etiquetas | V0.24.0 Suporte |
| sistema() | Implementação interna dos arquivos do sistema, integrando a classificação de rede | V0.24.0 Suporte |
| padrões () | A política padrão é atualmente sistema | V0.24.0 Suporte |
| Correntes (iwordtag ... outras) | Método da cadeia, suporta a integração do usuário para implementar várias políticas | V0.24.0 Suporte |
O formato das tags de palavras sensíveis que padrão é as seguintes敏感词tag1,tag2 , o que significa que as tags das敏感词são TAG1 e TAG2.
por exemplo
五星红旗 政治,国家
Isso também é recomendado para todos os conteúdos da linha de arquivo e conteúdo especificado da string. Se não estiver satisfeito, basta implementá -lo de maneira personalizada.
Começando com v0.24.0, a tag Palavra padrão é WordTags.system() .
Nota: Atualmente, as estatísticas de dados são da Internet e há muitas omissões. Todo mundo também pode corrigir o problema e continuar a melhorar ...
SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance ()
. wordTag ( WordTags . system ())
. init ();
Set < String > tagSet = sensitiveWordBs . tags ( "博彩" );
Assert . assertEquals ( "[3]" , tagSet . toString ());Aqui, para otimizar o tamanho da compressão, as categorias correspondentes são representadas por números.
A lista de números de significado é a seguinte:
0 政治
1 毒品
2 色情
3 赌博
4 违法
Aqui, tomamos o arquivo como exemplo para demonstrar como usá -lo.
final String path = "~ \ test \ resources \ dict_tag_test.txt" ;
// 演示默认方法
IWordTag wordTag = WordTags . file ( path );
SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance ()
. wordTag ( wordTag )
. init ();
Set < String > tagSet = sensitiveWordBs . tags ( "零售" );
Assert . assertEquals ( "[广告, 网络]" , tagSet . toString ());
// 演示指定分隔符
IWordTag wordTag2 = WordTags . file ( path , " " , "," );
SensitiveWordBs sensitiveWordBs2 = SensitiveWordBs . newInstance ()
. wordTag ( wordTag2 )
. init ();
Set < String > tagSet2 = sensitiveWordBs2 . tags ( "零售" );
Assert . assertEquals ( "[广告, 网络]" , tagSet2 . toString ()); Onde dict_tag_test.txt Nosso conteúdo personalizado é o seguinte:
零售 广告,网络
Quando obtemos palavras sensíveis, podemos definir a estratégia de processamento de resultados correspondente para obter as informações correspondentes da tag de palavra sensível
// 自定义测试标签类
IWordTag wordTag = WordTags . lines ( Arrays . asList ( "天安门 政治,国家,地址" ));
// 指定初始化
SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance ()
. wordTag ( wordTag )
. init ()
;
List < WordTagsDto > wordTagsDtoList1 = sensitiveWordBs . findAll ( "天安门" , WordResultHandlers . wordTags ());
Assert . assertEquals ( "[WordTagsDto{word='天安门', tags=[政治, 国家, 地址]}]" , wordTagsDtoList1 . toString ()); Personalizamos as tags das palavras -chave天安门e, em seguida, especificamos que a estratégia de processamento de resultados do Findall é WordResultHandlers.wordTags() e podemos obter a lista de tags correspondente enquanto obtém palavras sensíveis.
Às vezes, queremos projetar o carregamento de palavras sensíveis em dinâmica, como a modificação do console, que pode entrar em vigor em tempo real.
v0.0.13 suporta esse recurso.
Para implementar esse recurso e ser compatível com funções anteriores, definimos duas interfaces.
A interface é a seguinte, você pode personalizar sua própria implementação.
A lista retornada significa que a palavra é uma palavra sensível.
/**
* 拒绝出现的数据-返回的内容被当做是敏感词
* @author binbin.hou
* @since 0.0.13
*/
public interface IWordDeny {
/**
* 获取结果
* @return 结果
* @since 0.0.13
*/
List < String > deny ();
}por exemplo:
public class MyWordDeny implements IWordDeny {
@ Override
public List < String > deny () {
return Arrays . asList ( "我的自定义敏感词" );
}
}A interface é a seguinte, você pode personalizar sua própria implementação.
A lista retornada significa que a palavra não é uma palavra sensível.
/**
* 允许的内容-返回的内容不被当做敏感词
* @author binbin.hou
* @since 0.0.13
*/
public interface IWordAllow {
/**
* 获取结果
* @return 结果
* @since 0.0.13
*/
List < String > allow ();
}como:
public class MyWordAllow implements IWordAllow {
@ Override
public List < String > allow () {
return Arrays . asList ( "五星红旗" );
}
}Depois que a interface é personalizada, é claro, ela precisa ser especificada para entrar em vigor.
Para fazer uso mais elegante, projetamos a classe de inicialização SensitiveWordBs .
Você pode especificar palavras sensíveis através do worddeny (), wordallow () especifica palavras não sensíveis e inicializar palavras sensíveis dicionário através do init ().
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( WordDenys . defaults ())
. wordAllow ( WordAllows . defaults ())
. init ();
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( wordBs . contains ( text ));Nota: init () é demorado para construir a palavra sensível DFA. Geralmente é recomendável que seja inicializado apenas uma vez ao aplicar a inicialização. Em vez de repetir a inicialização!
Podemos testar a implementação personalizada, como segue:
String text = "这是一个测试,我的自定义敏感词。" ;
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( new MyWordDeny ())
. wordAllow ( new MyWordAllow ())
. init ();
Assert . assertEquals ( "[我的自定义敏感词]" , wordBs . findAll ( text ). toString ()); Aqui está o único em que我的自定义敏感词são palavras sensíveis, e测试não são palavras sensíveis.
Obviamente, aqui estão todas as nossas implementações personalizadas. Geralmente, é recomendável usar a configuração padrão + configuração personalizada do sistema.
O método a seguir pode ser usado.
O método WordDenys.chains() mescla várias implementações no mesmo iworddeny.
O método WordAllows.chains() mescla várias implementações no mesmo iDordAlow.
exemplo:
String text = "这是一个测试。我的自定义敏感词。" ;
IWordDeny wordDeny = WordDenys . chains ( WordDenys . defaults (), new MyWordDeny ());
IWordAllow wordAllow = WordAllows . chains ( WordAllows . defaults (), new MyWordAllow ());
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( wordDeny )
. wordAllow ( wordAllow )
. init ();
Assert . assertEquals ( "[我的自定义敏感词]" , wordBs . findAll ( text ). toString ());Todos eles usam a configuração padrão e a configuração personalizada do sistema ao mesmo tempo.
Nota: Inicializamos novos Wordbs, então use novos Wordbs para julgar. Em vez de usar o método anterior do SensitiveWordHelper Tool, a configuração do método da ferramenta é o padrão!
No uso real, por exemplo, você pode modificar a configuração da página e entrar em vigor em tempo real.
Os dados são armazenados no banco de dados. A seguir, é apresentado um exemplo de pseudo-código. Você pode se referir a SpringsensitivewordConfig.java
Necessário, versão v0.0.15 e acima.
O pseudo-código simplificado é o seguinte e a fonte dos dados é um banco de dados.
MyDDWordAlow e MyDDWordDeny são classes de implementação personalizadas com base em bancos de dados como fonte.
@ Configuration
public class SpringSensitiveWordConfig {
@ Autowired
private MyDdWordAllow myDdWordAllow ;
@ Autowired
private MyDdWordDeny myDdWordDeny ;
/**
* 初始化引导类
* @return 初始化引导类
* @since 1.0.0
*/
@ Bean
public SensitiveWordBs sensitiveWordBs () {
SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance ()
. wordAllow ( WordAllows . chains ( WordAllows . defaults (), myDdWordAllow ))
. wordDeny ( myDdWordDeny )
// 各种其他配置
. init ();
return sensitiveWordBs ;
}
}A inicialização do vocabulário sensível é demorado, por isso é recomendável fazer a inicialização do início uma vez quando o programa é iniciado.
Após a v0.6.0, adicione o teste de referência correspondente.
Benchmarktimestest
O ambiente de teste é um caderno normal:
处理器 12th Gen Intel(R) Core(TM) i7-1260P 2.10 GHz
机带 RAM 16.0 GB (15.7 GB 可用)
系统类型 64 位操作系统, 基于 x64 的处理器
PS: ambientes diferentes variam, mas a proporção é basicamente estável.
Dados de teste: mais de 100 string, loop 10W vezes.
| Número de série | Cena | demorado | Observação |
|---|---|---|---|
| 1 | Apenas faça palavras sensíveis sem qualquer conversão de formato | 1470ms, cerca de 7,2w QPs | Perseguindo o desempenho extremo, você pode configurá -lo assim |
| 2 | Faça apenas palavras sensíveis, apoie toda a conversão de formato | 2744ms, cerca de 3,7W QPs | Conheça a maioria dos cenários |
Remova palavras sensíveis de caracteres chineses individuais. Na China, as frases devem ser consideradas uma única palavra para reduzir a taxa de julgamento.
Suporta mudanças de palavras sensíveis individuais?
Remover, adicionar, editar?
Suporte sensível à interface da tag de palavra
Suporte a tag ao processar palavras sensíveis
Comparação de uso de memória + otimização de worddata
Os usuários especificam frases personalizadas e permitem a combinação de frases especificadas a serem obtidas, tornando -a mais flexível
Política de combinação FormatCombine/checkCombine/AllowDenyCombina, permitindo a personalização do usuário.
Otimização da estratégia de verificação de palavras, travessal unificado + conversão
Adicionar otimizações de Threadlocal e outras de desempenho
Console de palavras sensíveis à palavra sensível-palavra
Como apoiar a implantação distribuída na versão sensível-palavra-ADMIN v1.3.0?
01-BEGINNER da ferramenta de palavras sensíveis ao código aberto
02-Como implementar uma ferramenta de palavra sensível? Esclarecer a ideia de implementar palavras proibidas
03 Support Word Stopword Otimização de palavras e símbolos especiais
04-dicionário de palavras sensíveis emagrece
05 Explicação detalhada do algoritmo DFA de palavras sensíveis (algoritmo de árvore de trie)
06 Palavras sensíveis (palavras sujas) Como ignorar caracteres sem sentido? Alcançar um melhor efeito de filtragem
V0.10.0 Suporte preliminar para tag de classificação de palavras sujas
v0.11.0 - Novos recursos de palavras sensíveis: ignore caracteres sem sentido, dicionário de tag word tag
v0.12.0 Words-Word/Dirty Word Rotting Capacidade é ainda mais aprimorada
V0.13.0 A versão do recurso de palavra sensível suporta correspondência completa de palavras em palavras em inglês
V0.16.1 Dictionary Memory Resource Release de novos recursos de palavras sensíveis
v0.19.0 - Palavras sensíveis com novos recursos de palavras sensíveis editadas individualmente sem inicialização repetida
v0.20.0 As novas características de palavras sensíveis correspondem a todos os números, não correspondências parciais
V0.21.0 Listas de trabalho com novos recursos de palavras sensíveis suportam edição única, corrigindo o problema quando as listas de braços contêm listas negras
Pinyin para Pinyin
pinyin2hanzi pinyin para caracteres chineses
segmento de alto desempenho segmentação de palavras chinesa
OpenCc4J Chinesa Tradicional Chinês Simplificado Conversão Chinesa
similaridade de caráter chinesa de NLP-Hanzi-Mimilar
Detecção de ortografia que verifica palavras
Palavras sensíveis à palavra sensível