Le mot sensible est un outil de mot sensible haute performance basé sur l'algorithme DFA.
Expérience en ligne
Si vous avez des maladies difficiles et compliquées, vous pouvez rejoindre: Technical Exchange Group
L'admin sensible du mot sensible est l'application de console correspondante. Les fonctions sont actuellement dans les premiers stades de développement et la version MVP est disponible.
Bonjour à tous, je suis Lao Ma.
J'ai toujours voulu implémenter un outil de mot sensible simple et facile à utiliser, j'ai donc implémenté cet outil open source.
Sur la base de l'implémentation de l'algorithme DFA, le contenu du thésaurus sensible comprend actuellement 6W + (fichier source 18W +, après une suppression).
Dans le stade ultérieur, le thésaurus sensible sera en continu optimisé et complété, et les performances de l'algorithme seront encore améliorées.
V0.24.0 a commencé à soutenir la classification et le raffinement des mots sensibles, mais la charge de travail est relativement importante, il existe donc des omissions inévitablement.
Bienvenue aux améliorations des relations publiques, aux demandes de GitHub ou à le groupe d'échange technique pour communiquer et se vanter!
6w + thésaurus, et optimisation continue et mise à jour
Basé sur la mise en œuvre de l'API courante, une utilisation élégante et concise
Sur la base de l'algorithme DFA, les performances sont 7W + QPS, l'application est insensible
Soutenir les opérations communes telles que le jugement, le retour et la désensibilisation des mots sensibles
Prend en charge la conversion de format commune
Échange de demi-largeur pleine largeur, échange de cas anglais, formes communes de nombres, chinois traditionnels et chinois simplifiés, formes communes d'échanges anglais, ignorant les mots en double, etc.
Prise en charge de la détection sensible des mots, de la détection des e-mails, de la détection numérique, de la détection du site Web, IPv4, etc.
Prend en charge les politiques de remplacement personnalisées
Prend en charge les mots sensibles définis par l'utilisateur
Prend en charge les mises à jour dynamiques de données (personnalisation des utilisateurs), efficace en temps réel
Prend en charge l'interface de balise + implémentation de classification intégrée pour les mots sensibles
Assistance Saute certains caractères spéciaux pour rendre la correspondance plus flexible
Prend en charge l'ajout / modification unique des listes en noir et blanc, sans initialisation complète
Change_log.md
Parfois, il existe une console pour les mots sensibles, ce qui le rend plus flexible et pratique à configurer.
Comment implémenter le service de console de mots sensibles hors de la boîte?
Un grand nombre de fichiers de balises de mot sensibles ont été réglés, ce qui peut rendre nos mots sensibles plus pratiques.
Ces deux documents peuvent être lus dans l'article ci-dessous:
V0.11.0-New Fonctionnalités des mots sensibles et des fichiers de balises correspondantes
Actuellement, V0.24.0 a des balises de mots intégrées, et il est recommandé de passer à la dernière version si nécessaire.
Open Source n'est pas facile. Si ce projet vous est utile, vous pouvez inviter le Lao Ma à prendre une tasse de thé au lait.

JDK1.8 +
Maven 3.x +
< dependency >
< groupId >com.github.houbb</ groupId >
< artifactId >sensitive-word</ artifactId >
< version >0.24.0</ version >
</ dependency > SensitiveWordHelper est une classe d'outils pour les mots sensibles. Les méthodes de base sont les suivantes:
Remarque: SensitiveWordHelper fournit des configurations par défaut. Si vous souhaitez effectuer des configurations personnalisées flexibles, veuillez vous référer à la configuration de la fonction de classe de démarrage
| méthode | paramètre | Valeur de retour | illustrer |
|---|---|---|---|
| contient (chaîne) | La chaîne à vérifier | Valeur booléenne | Vérifiez que la chaîne contient des mots sensibles |
| remplacer (chaîne, iSensitivewordReplace) | Remplacez les mots sensibles par une stratégie de remplacement spécifiée | Chaîne | Renvoie la chaîne désensibilisée |
| remplacer (String, char) | Utilisez le charbon spécifié pour remplacer le mot sensible | Chaîne | Renvoie la chaîne désensibilisée |
| remplacer (chaîne) | Utiliser * pour remplacer les mots sensibles | Chaîne | Renvoie la chaîne désensibilisée |
| findall (string) | La chaîne à vérifier | Liste des chaînes | Renvoie tous les mots sensibles dans la chaîne |
| findFirst (string) | La chaîne à vérifier | Chaîne | Renvoie le premier mot sensible dans la chaîne |
| findall (String, iwordResulthandler) | Classe de traitement des résultats iwordResulthandler | Liste des chaînes | Renvoie tous les mots sensibles dans la chaîne |
| findFirst (String, iwordResulthandler) | Classe de traitement des résultats iwordResulthandler | Chaîne | Renvoie le premier mot sensible dans la chaîne |
| Tags (chaîne) | Obtenez des balises pour les mots sensibles | Chaîne de mots sensible | Retourner à la liste des balises pour les mots sensibles |
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( SensitiveWordHelper . contains ( text )); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
String word = SensitiveWordHelper . findFirst ( text );
Assert . assertEquals ( "五星红旗" , word );SensitivewordHelper.FindFirst (texte) équivaut à:
String word = SensitiveWordHelper . findFirst ( text , WordResultHandlers . word ()); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
List < String > wordList = SensitiveWordHelper . findAll ( text );
Assert . assertEquals ( "[五星红旗, 毛主席, 天安门]" , wordList . toString ());Renvoie toutes les mots sensibles que l'utilisation est similaire à SensitivewordHelper.FindFirst () et prend également en charge la spécification des classes de traitement des résultats.
SensitivewordHelper.Findall (texte) est équivalent à:
List < String > wordList = SensitiveWordHelper . findAll ( text , WordResultHandlers . word ());Wordresulthandlers.raw () peut conserver les informations sur les indices et les informations de catégorie correspondantes:
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 prend en charge cette fonctionnalité.
Description de la scène: Parfois, nous voulons que différents mots sensibles aient des résultats de remplacement différents. Par exemple, [le jeu] est remplacé par [E-Sports], et [le chômage] est remplacé par [un emploi flexible].
Certes, il est normal d'utiliser un remplacement régulier des chaînes à l'avance, mais les performances sont moyennes.
Exemple d'utilisation:
/**
* 自定替换策略
* @since 0.2.0
*/
@ Test
public void defineReplaceTest () {
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
ISensitiveWordReplace replace = new MySensitiveWordReplace ();
String result = SensitiveWordHelper . replace ( text , replace );
Assert . assertEquals ( "国家旗帜迎风飘扬,教员的画像屹立在***前。" , result );
} Parmi eux, MySensitiveWordReplace est notre politique de remplacement personnalisée, qui est implémentée comme suit:
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 ( '*' );
}
}
}
} Nous effectuons une cartographie fixe pour certains mots, et les autres sont convertis en * par défaut.
IwordResulthandler peut traiter les résultats des mots sensibles et permettre aux utilisateurs de les personnaliser.
Voir Classe d'outils WordResultHandlers pour la mise en œuvre intégrée:
Seuls les mots sensibles sont conservés.
Conserver des informations liées aux mots sensibles, y compris les indices de début et de fin de mots sensibles.
Dans le même temps, les mots et les informations de l'étiquette des mots correspondants sont conservés.
Voir SensitivewordHelPertest pour tous les cas de test
1) Exemples de base
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 ()); Nous spécifions les informations de balise du mot correspondant dans le fichier 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 ());Les caractéristiques suivantes visent principalement divers traitements ciblant diverses situations, afin d'améliorer autant que possible le taux de succès des mots sensibles.
Il s'agit d'une longue bataille d'infraction et de défense.
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 );Ici, la conversion des formes courantes de numérique est mise en œuvre.
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 ());Les informations personnelles telles que l'adresse e-mail ne sont pas activées par défaut.
final String text = "楼主好人,邮箱 [email protected]" ;
List < String > wordList = SensitiveWordBs . newInstance (). enableEmailCheck ( true ). init (). findAll ( text );
Assert . assertEquals ( "[[email protected]]" , wordList . toString ());Il est généralement utilisé pour filtrer les informations publicitaires telles que le numéro de téléphone mobile / QQ, et n'est pas activé par défaut.
Après V0.2.1, les longueurs détectées par numCheckLen(长度) sont prises en charge.
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 ());Utilisé pour filtrer les informations d'URL communes, non activées par défaut.
V0.18.0 optimise la détection de l'URL, qui est plus stricte et réduit le taux de mauvais jugement
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 Support
Évitez que les utilisateurs contournent la détection de l'URL via IP, etc., qui n'est pas activé par défaut.
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 ());Les fonctionnalités ci-dessus sont toutes activées par défaut, et parfois l'entreprise doit définir de manière flexible les fonctionnalités de configuration associées.
V0.0.14 ouvre donc la configuration de la propriété.
Pour être plus élégant, la définition est uniformément utilisée par l'API fluide.
Les utilisateurs peuvent utiliser SensitiveWordBs pour le définir comme suit:
Remarque: Après la configuration, utilisez notre objet SensitiveWordBs nouvellement défini au lieu de la méthode de l'outil précédent. La configuration de la méthode de l'outil est entièrement par défaut.
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 ));La description de chaque configuration est la suivante:
| Numéro de série | méthode | illustrer | valeur par défaut |
|---|---|---|---|
| 1 | Ignorecase | Ignorer le cas | vrai |
| 2 | ignorer la largeur | Ignorez les coins arrondis du demi-corner | vrai |
| 3 | ignorémstyle | Ignorez l'écriture de nombres | vrai |
| 4 | Ignorer le chinéstie | Ignorer le format d'écriture chinois | vrai |
| 5 | Ignorenglishstyle | Ignorer le format d'écriture anglais | vrai |
| 6 | Ignorerereat | Ignorer les mots en double | FAUX |
| 7 | enable | S'il faut permettre la détection numérique. | FAUX |
| 8 | activermailcheck | La détection des e-mails est activée | FAUX |
| 9 | Activer | S'il faut permettre la détection des liens | FAUX |
| 10 | activerIpv4check | S'il faut activer la détection IPv4 | FAUX |
| 11 | activerwordcheck | S'il faut permettre une détection de mots sensible | vrai |
| 12 | dégraisser | Détection numérique, personnalisez la longueur spécifiée. | 8 |
| 13 | wordtag | Les balises de mots correspondantes | aucun |
| 14 | Charignore | Personnages ignorés | aucun |
| 15 | condition à l'origine | Traitement supplémentaire pour la correspondance des mots sensibles, comme limiter le besoin de matchs complets de mots anglais | Toujours vrai |
V0.16.1 est pris en charge. Parfois, nous devons libérer de la mémoire, ce qui peut être le suivant:
Sur les problèmes de recyclage de la mémoire
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. init ();
// 后续因为一些原因移除了对应信息,希望释放内存。
wordBs . destroy ();Scénario d'utilisation: Après l'initialisation, nous voulons ajouter / supprimer un seul mot au lieu de le réinitialiser complètement. Cette fonction est préparée à cela.
Version prise en charge: v0.19.0
addWord(word) ajoute des mots sensibles, en prenant en charge les mots / collections uniques
removeWord(word) supprime les mots sensibles, prend en charge les mots / collections uniques
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 ());Scénario d'utilisation: Après l'initialisation, nous voulons ajouter / supprimer un seul mot au lieu de le réinitialiser complètement. Cette fonction est préparée à cela.
Version prise en charge: v0.21.0
addWordAllow(word) ajoute une nouvelle liste blanche, prend en charge les mots / collections uniques
removeWordAllow(word) supprime les listes blanches, prend en charge les mots / collections uniques
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 ());Cette méthode est abandonnée . Il est recommandé d'utiliser la méthode d'addition incrémentielle ci-dessus pour éviter la charge complète. Pour la compatibilité, cette méthode demeure.
Comment utiliser: lors de l'appel de sensitiveWordBs.init() , reconstruisez le vocabulaire sensible basé sur iworddeny + iwordallow. Étant donné que l'initialisation peut prendre beaucoup de temps (deuxième niveau), toutes les optimisations à init n'affecteront pas l'ancienne fonction de vocabulaire lorsqu'elle n'est pas terminée, et la nouvelle prévaudra après l'achèvement .
@ Component
public class SensitiveWordService {
@ Autowired
private SensitiveWordBs sensitiveWordBs ;
/**
* 更新词库
*
* 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法。
* 如果需要生效,则调用这个方法。
*
* 说明:重新初始化不影响旧的方法使用。初始化完成后,会以新的为准。
*/
public void refresh () {
// 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法,然后调用这个方法。
sensitiveWordBs . init ();
}
} Comme mentionné ci-dessus, vous pouvez déclencher activement l'initialisation de sensitiveWordBs.init(); Lorsque le lexique de la base de données change et que la base de données doit prendre effet.
D'autres utilisations restent les mêmes sans redémarrer l'application.
Version prise en charge: v0.13.0
Parfois, nous pouvons vouloir limiter davantage les mots sensibles correspondants, par exemple, bien que nous définissions [AV] comme un mot sensible, nous ne voulons pas [devons] être appariés.
Vous pouvez personnaliser l'interface WordrersultCondition et implémenter vos propres politiques.
La stratégie intégrée dans WordResultConditions#alwaysTrue() est toujours vraie, tandis que WordResultConditions#englishWordMatch() exige que la langue anglaise soit correspondre au mot complet.
La classe d'outils WordrersultConditions peut obtenir des politiques de correspondance
| accomplir | illustrer | Version prise en charge |
|---|---|---|
| Toujours | Toujours vrai | |
| EnglishwordMatch | Mot anglais Mordage complet | v0.13.0 |
| EnglishwordNummatch | Mot anglais / numéro Full Word correspondant | v0.20.0 |
| wordtags | Ceux qui satisfont des balises spécifiques, comme se concentrer uniquement sur les balises [publicitaires] | v0.23.0 |
| chaînes (iwordResultCondition ... conditions) | Prend en charge la spécification de plusieurs conditions et les satisfaire en même temps | v0.23.0 |
Situation par défaut d'origine:
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 ());Nous pouvons spécifier que l'anglais doit correspondre au mot complet.
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 ());Bien sûr, des stratégies plus complexes peuvent être mises en œuvre au besoin.
Version prise en charge: v0.23.0
Nous ne pouvons retourner que des mots sensibles affiliés à une certaine étiquette.
Nous avons spécifié deux mots sensibles: produit, av
MyWordTag est une implémentation de balise de mots sensible que nous définissons:
/**
* 自定义单词标签
* @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 );
}
}Par exemple, nous simulons deux classes d'implémentation différentes, chacune se concentrant sur une balise de mots différente.
// 只关心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 ());Nos mots sensibles sont généralement plus continus, comme [le chapeau idiot]
Ensuite, il y a une découverte intelligente que vous pouvez ajouter des personnages au milieu, comme [idiot! @ # $ Hat] pour sauter la détection, mais la puissance d'attaque de la juron n'est pas réduite.
Alors, comment gérer ces scénarios similaires?
Nous pouvons spécifier des ensembles de sauts de caractères spéciaux et ignorer ces caractères dénués de sens.
V0.11.0 commence le support
La stratégie de caractère correspondant à Charignore peut être définie de manière flexible par les utilisateurs.
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 ());Parfois, nous voulons ajouter une étiquette classifiée à des mots sensibles: comme la situation sociale, la violence, etc.
De cette façon, plus de caractéristiques peuvent être effectuées en fonction des étiquettes, etc., comme le traitement uniquement d'un certain type d'étiquette.
Version prise en charge: v0.10.0
Version des principales fonctionnalités: v0.24.0
Ce n'est qu'une interface abstraite, et les utilisateurs peuvent définir la mise en œuvre par eux-mêmes. Par exemple, à partir de la requête de base de données, de la lecture de fichiers, des appels API, etc.
public interface IWordTag {
/**
* 查询标签列表
* @param word 脏词
* @return 结果
*/
Set < String > getTag ( String word );
} Afin de faciliter l'utilisation dans la plupart des situations, certaines stratégies de scène sont mises en œuvre dans WordTags
| Méthode d'implémentation | illustrer | Remarque |
|---|---|---|
| aucun() | Implémentation vide | V0.10.0 Support |
| fichier (chaîne filepath) | Spécifiez le chemin du fichier | V0.10.0 Support |
| fichier (chaîne filepath, chaîne wordsplit, string tagsplit) | Spécifiez les chemins de fichier, ainsi que les séparateurs de mots et les séparateurs de balises | V0.10.0 Support |
| Carte (carte finale <chaîne, set> wordtagmap) | Initialisation selon la carte | V0.24.0 Support |
| lignes (lignes de collecte) | Liste des chaînes | V0.24.0 Support |
| lignes (lignes de collecte, chaîne wordsplit, string tagspli) | Liste des chaînes, ainsi que des séparateurs de mots et des séparateurs d'étiquettes | V0.24.0 Support |
| système() | Implémentation intégrée des fichiers système, intégrant la classification du réseau | V0.24.0 Support |
| par défaut () | La stratégie par défaut est actuellement le système | V0.24.0 Support |
| chaînes (iwordtag ... autres) | Méthode de la chaîne, prend en charge l'intégration des utilisateurs pour implémenter plusieurs stratégies | V0.24.0 Support |
Le format des balises de mot sensibles nous par défaut les敏感词tag1,tag2 , ce qui signifie que les balises des敏感词sont Tag1 et Tag2.
Par exemple
五星红旗 政治,国家
Ceci est également recommandé pour tous les contenus de la ligne de fichiers et le contenu de la chaîne spécifié. S'il n'est pas satisfait, implémentez-le simplement de manière personnalisée.
En commençant par V0.24.0, la balise Word par défaut est WordTags.system() .
Remarque: Actuellement, les statistiques de données proviennent d'Internet et il existe de nombreuses omissions. Tout le monde est également le bienvenu pour corriger le problème et continuer à s'améliorer ...
SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance ()
. wordTag ( WordTags . system ())
. init ();
Set < String > tagSet = sensitiveWordBs . tags ( "博彩" );
Assert . assertEquals ( "[3]" , tagSet . toString ());Ici, afin d'optimiser la taille de la compression, les catégories correspondantes sont représentées par des nombres.
La liste des nombres de sens est la suivante:
0 政治
1 毒品
2 色情
3 赌博
4 违法
Ici, nous prenons le fichier comme exemple pour montrer comment l'utiliser.
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 ()); Où dict_tag_test.txt notre contenu personnalisé est le suivant:
零售 广告,网络
Lorsque nous obtenons des mots sensibles, nous pouvons définir la stratégie de traitement des résultats correspondante pour obtenir les informations de tag de mot sensible correspondantes
// 自定义测试标签类
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 ()); Nous personnalisons les balises pour les mots clés天安门, puis spécifions que la stratégie de traitement des résultats de Findall est WordResultHandlers.wordTags() , et nous pouvons obtenir la liste de balises correspondante tout en obtenant des mots sensibles.
Parfois, nous voulons concevoir le chargement des mots sensibles en dynamique, tels que la modification de la console, qui peut ensuite prendre effet en temps réel.
V0.0.13 prend en charge cette fonctionnalité.
Pour implémenter cette fonctionnalité et être compatible avec les fonctions précédentes, nous avons défini deux interfaces.
L'interface est la suivante, vous pouvez personnaliser votre propre implémentation.
La liste retournée signifie que le mot est un mot sensible.
/**
* 拒绝出现的数据-返回的内容被当做是敏感词
* @author binbin.hou
* @since 0.0.13
*/
public interface IWordDeny {
/**
* 获取结果
* @return 结果
* @since 0.0.13
*/
List < String > deny ();
}Par exemple:
public class MyWordDeny implements IWordDeny {
@ Override
public List < String > deny () {
return Arrays . asList ( "我的自定义敏感词" );
}
}L'interface est la suivante, vous pouvez personnaliser votre propre implémentation.
La liste retournée signifie que le mot n'est pas un mot sensible.
/**
* 允许的内容-返回的内容不被当做敏感词
* @author binbin.hou
* @since 0.0.13
*/
public interface IWordAllow {
/**
* 获取结果
* @return 结果
* @since 0.0.13
*/
List < String > allow ();
}comme:
public class MyWordAllow implements IWordAllow {
@ Override
public List < String > allow () {
return Arrays . asList ( "五星红旗" );
}
}Une fois l'interface personnalisée, bien sûr, il doit être spécifié pour prendre effet.
Pour être plus élégant, nous avons conçu les SensitiveWordBs de la classe de démarrage.
Vous pouvez spécifier des mots sensibles via WordDeny (), WordAllow () spécifie des mots non sensibles et initialiser le dictionnaire de mots sensibles via init ().
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( WordDenys . defaults ())
. wordAllow ( WordAllows . defaults ())
. init ();
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( wordBs . contains ( text ));Remarque: init () prend du temps pour construire le mot sensible DFA. Il est généralement recommandé qu'il soit initialisé une seule fois lors de l'application de l'initialisation. Au lieu de répéter l'initialisation!
Nous pouvons tester l'implémentation personnalisée, comme suit:
String text = "这是一个测试,我的自定义敏感词。" ;
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( new MyWordDeny ())
. wordAllow ( new MyWordAllow ())
. init ();
Assert . assertEquals ( "[我的自定义敏感词]" , wordBs . findAll ( text ). toString ()); Voici le seul où我的自定义敏感词sont des mots sensibles, et测试ne sont pas des mots sensibles.
Bien sûr, voici toutes nos implémentations personnalisées. Il est généralement recommandé d'utiliser la configuration par défaut + configuration personnalisée du système.
La méthode suivante peut être utilisée.
La méthode WordDenys.chains() fusionne plusieurs implémentations dans la même iworddeny.
La méthode WordAllows.chains() fusionne plusieurs implémentations dans le même iwordallow.
exemple:
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 ());Tous utilisent la configuration par défaut du système et la configuration personnalisée en même temps.
Remarque: nous initialisons de nouveaux wordbs, alors utilisons de nouveaux wordbs pour juger. Au lieu d'utiliser la méthode de l'outil SensitiveWordHelper précédent, la configuration de la méthode de l'outil est la valeur par défaut!
Dans une utilisation réelle, par exemple, vous pouvez modifier la configuration de la page, puis prendre effet en temps réel.
Les données sont stockées dans la base de données. Ce qui suit est un exemple de pseudo-code. Vous pouvez vous référer à SpringsensitivewordConfig.java
Requis, version v0.0.15 et plus.
Le pseudo-code simplifié est le suivant et la source des données est une base de données.
MyDDWORDALLOW et MYDDWORDDENY sont des classes d'implémentation personnalisées basées sur des bases de données comme source.
@ 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 ;
}
}L'initialisation du vocabulaire sensible prend du temps, il est donc recommandé de faire l'initialisation de l'initialisation une fois lorsque le programme commence.
Après V0.6.0, ajoutez le test de référence correspondant.
Benchmarktimest
L'environnement de test est un cahier normal:
处理器 12th Gen Intel(R) Core(TM) i7-1260P 2.10 GHz
机带 RAM 16.0 GB (15.7 GB 可用)
系统类型 64 位操作系统, 基于 x64 的处理器
PS: Différents environnements varieront, mais la proportion est essentiellement stable.
Données de test: 100+ chaîne, boucle 10w fois.
| Numéro de série | Scène | prend du temps | Remarque |
|---|---|---|---|
| 1 | Ne faites que des mots sensibles sans aucune conversion de format | 1470 ms, environ 7,2W QPS | En poursuivant des performances extrêmes, vous pouvez le configurer comme celui-ci |
| 2 | Faites uniquement des mots sensibles, soutenez toute la conversion de format | 2744 ms, environ 3,7 W QPS | Rencontrer la plupart des scénarios |
Retirez les mots sensibles des caractères chinois individuels. En Chine, les phrases doivent être considérées comme un seul mot pour réduire le taux de mauvaise évaluation.
Prend en charge les changements de mots sensibles individuels?
Supprimer, ajouter, modifier?
Prise en charge de l'interface de balise de mot sensible
Prise en charge des balises lors du traitement des mots sensibles
Comparaison d'utilisation de la mémoire + optimisation de WordData
Les utilisateurs spécifient des phrases personnalisées et permettent l'obtention de la combinaison de phrases spécifiées, ce qui le rend plus flexible
FormatCombine / CheckCombine / AwardEnyCombine Combination Politique, permettant la personnalisation des utilisateurs.
Optimisation de la stratégie de vérification des mots, traversée unifiée + conversion
Ajouter des optimisations threadlocal et autres performances
console sensible de mots sensibles sensibles v1.2.0 open source
Comment prendre en charge le déploiement distribué dans la version sensible du mot-aîné v1.3.0?
01-bête de l'outil de mot sensible open source
02-How pour implémenter un outil de mots sensible? Clarifier l'idée de mettre en œuvre des mots interdits
MOT DE PRÉSENTATION 03 MOT DE MOT DE MOT STOP OPTIMILISATION DES MOTS ET SYMBOLES SPÉCIALES
04-Dictionnaire de mots sensibles minceur
Explication 05 Détaillée de l'algorithme DFA des mots sensibles (algorithme Trie Tree)
Mots sensibles 06 (mots sales) Comment ignorer les personnages dénués de sens? Obtenir un meilleur effet de filtrage
V0.10.0 Support préliminaire pour la balise de classification des mots sales
V0.11.0 - Nouvelles fonctionnalités des mots sensibles: ignorez les caractères dénués de sens, dictionnaire Word Tag
La capacité de l'étiquetage des mots / mot sales sensible à la v0.12.0 est encore amélioré
V0.13.0 La version de fonction de fonctionnalité sensible à la version prend en charge la correspondance de mots complet en anglais mots
V0.16.1 Mémoire de dictionnaire Libération de nouvelles fonctionnalités des mots sensibles
V0.19.0 - Mots sensibles avec de nouvelles caractéristiques de mots sensibles modifiés individuellement sans initialisation répétée
v0.20.0 Les nouvelles caractéristiques des mots sensibles correspondent à tous les nombres, et non des correspondances partielles
V0.21.0 Les listes blanches avec de nouvelles fonctionnalités de mots sensibles prennent en charge l'édition unique, corrigeant le problème lorsque les listes blanches contiennent des listes noires
pinyin à pinyin
pinyin2hanzi pinyin aux caractères chinois
Segment segmentation des mots chinois de haute performance
opencc4j chinois chinois chinois simplifié chinois
NLP-Hanzi-Similar Chinese Characonity
Détection d'orthographe du vérificateur de mots
Mots sensibles des mots sensibles