Sensitive-Wordは、DFAアルゴリズムに基づいた高性能センシティブワードツールです。
オンラインエクスペリエンス
困難で複雑な病気がある場合は、参加できます:技術交換グループ
Sensitive-Word-Adminは、対応するコンソールアプリケーションです。機能は現在、開発の初期段階にあり、MVPバージョンが利用可能です。
みなさん、こんにちは、私はラオスです。
私は常にシンプルで使いやすい敏感なワードツールを実装したいと思っていたので、このツールのオープンソースを実装しました。
DFAアルゴリズムの実装に基づいて、敏感なシソーラスの内容には現在、6W+(1つの削除後のソースファイル18W+)が含まれています。
後の段階では、敏感なシソーラスが継続的に最適化および補足され、アルゴリズムの性能がさらに向上します。
V0.24.0は、敏感な単語の分類と改良をサポートし始めていますが、ワークロードは比較的大きいため、必然的に省略があります。
PRの改善、GitHubリクエストへようこそ、または技術交換グループに参加して、コミュニケーションと自慢してください!
6W+シソーラス、および継続的な最適化と更新
Fluent-APIの実装に基づいて、エレガントで簡潔な使用
DFAアルゴリズムに基づいて、パフォーマンスは7W+ QPSで、アプリケーションは無感覚です
敏感な言葉の判断、復帰、脱感作などの一般的な操作をサポートする
一般的な形式の変換をサポートします
全幅の半幅のインターチェンジ、英語のケースインターチェンジ、数字の一般的な形式、伝統的な中国語および単純化された中国語の一般的な形式の英語のインターチェンジ、重複した単語など。
敏感な単語検出、電子メール検出、デジタル検出、ウェブサイトの検出、IPv4などをサポートします。
カスタム交換ポリシーをサポートします
ユーザー定義の敏感な単語とホワイトリストをサポートします
リアルタイムで効果的な動的データの更新(ユーザーのカスタマイズ)をサポートします
タグインターフェイス +ビルトイン分類の実装をサポートします。
特殊文字をスキップしてマッチングをより柔軟にすることをサポートする
完全な初期化なしで、白黒リストの単一の追加/変更をサポートします
change_log.md
繊細な単語用のコンソールがある場合があり、それがより柔軟で構成が便利になるようにします。
容易な単語コンソールサービスを箱から出して実装する方法は?
多数の敏感な単語タグファイルが整理されているため、敏感な単語をより便利にすることができます。
これらの2つの資料は、以下の記事で読むことができます。
V0.11.0敏感な単語と対応するタグファイルの新しい機能
現在、v0.24.0にはワードタグが組み込まれており、必要に応じて最新バージョンにアップグレードすることをお勧めします。
オープンソースは簡単ではありません。このプロジェクトがあなたに役立つ場合は、ラオスを招待してミルクティーを飲むことができます。

JDK1.8+
Maven 3.x+
< dependency >
< groupId >com.github.houbb</ groupId >
< artifactId >sensitive-word</ artifactId >
< version >0.24.0</ version >
</ dependency >SensitiveWordHelperは、敏感な単語のためのツールクラスです。コアメソッドは次のとおりです。
注: SensitiveWordHelperデフォルトの構成を提供します。柔軟なカスタム構成を作成する場合は、ブートクラス機能構成を参照してください
| 方法 | パラメーター | 返品値 | 説明します |
|---|---|---|---|
| contains(string) | 検証する文字列 | ブール値 | 文字列に敏感な単語が含まれていることを確認します |
| 交換(文字列、IsensitiveWordReplace) | 敏感な単語を指定された交換戦略に置き換えます | 弦 | 脱感作文字列を返します |
| 交換(文字列、char) | 指定されたCharを使用して、敏感な単語を置き換えます | 弦 | 脱感作文字列を返します |
| 交換(文字列) | *を使用して、敏感な単語を置き換えます | 弦 | 脱感作文字列を返します |
| findall(string) | 検証する文字列 | 文字列のリスト | 文字列内のすべての敏感な単語を返します |
| FindFirst(String) | 検証する文字列 | 弦 | 文字列の最初の敏感な単語を返します |
| findall(string、iwordresulthandler) | iwordresulthandler結果処理クラス | 文字列のリスト | 文字列内のすべての敏感な単語を返します |
| FindFirst(String、iwordresulthandler) | iwordresulthandler結果処理クラス | 弦 | 文字列の最初の敏感な単語を返します |
| タグ(文字列) | 敏感な単語のタグを取得します | 敏感な単語文字列 | 敏感な単語のタグのリストに戻ります |
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( SensitiveWordHelper . contains ( text )); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
String word = SensitiveWordHelper . findFirst ( text );
Assert . assertEquals ( "五星红旗" , word );sensitiveWordHelper.findfirst(テキスト)は次のものと同等です。
String word = SensitiveWordHelper . findFirst ( text , WordResultHandlers . word ()); final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
List < String > wordList = SensitiveWordHelper . findAll ( text );
Assert . assertEquals ( "[五星红旗, 毛主席, 天安门]" , wordList . toString ());すべての敏感な単語の使用法は、sensitivewordhelper.findfirst()に似ており、結果処理クラスの指定もサポートします。
sensitiveWordHelper.findall(テキスト)は次のものと同等です。
List < String > wordList = SensitiveWordHelper . findAll ( text , WordResultHandlers . word ());wordresulthandlers.raw()は、対応するサブスクリプト情報とカテゴリ情報を保持できます。
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はこの機能をサポートしています。
シーンの説明:異なる敏感な単語が異なる交換結果を得ることを望んでいる場合があります。たとえば、[ゲーム]は[eスポーツ]に置き換えられ、[失業]は[柔軟な雇用]に置き換えられます。
確かに、事前に文字列を定期的に交換することは問題ありませんが、パフォーマンスは平均です。
使用例:
/**
* 自定替换策略
* @since 0.2.0
*/
@ Test
public void defineReplaceTest () {
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
ISensitiveWordReplace replace = new MySensitiveWordReplace ();
String result = SensitiveWordHelper . replace ( text , replace );
Assert . assertEquals ( "国家旗帜迎风飘扬,教员的画像屹立在***前。" , result );
}その中で、 MySensitiveWordReplaceカスタマイズされた交換ポリシーであり、次のように実装されています。
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 ( '*' );
}
}
}
}いくつかの単語のマッピングを固定し、その他はデフォルトで*に変換されます。
iwordresulthandlerは、敏感な単語の結果を処理し、ユーザーがそれらをカスタマイズできるようにすることができます。
組み込みの実装については、 WordResultHandlersツールクラスを参照してください。
敏感な単語のみが保存されます。
敏感な単語の最初の添え字と末端を含む、敏感な単語に関連する情報を保持します。
同時に、単語と対応する単語ラベル情報が保持されます。
すべてのテストケースについては、sensitivewordhelpertestを参照してください
1)基本的な例
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 ());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 ());その後の機能は、主にさまざまな状況をターゲットにするさまざまな処理を目的としており、敏感な単語のヒット率を可能な限り改善します。
これは長い攻撃と防衛の戦いです。
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 );ここでは、一般的な形式のデジタルの変換が実装されます。
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 ());電子メールアドレスなどの個人情報は、デフォルトでは有効になりません。
final String text = "楼主好人,邮箱 [email protected]" ;
List < String > wordList = SensitiveWordBs . newInstance (). enableEmailCheck ( true ). init (). findAll ( text );
Assert . assertEquals ( "[[email protected]]" , wordList . toString ());通常、携帯電話番号/QQなどの広告情報をフィルタリングするために使用され、デフォルトでは有効にされていません。
V0.2.1の後、 numCheckLen(长度)によって検出された長さがサポートされます。
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 ());デフォルトでは有効になっていない一般的なURL情報のフィルタリングに使用されます。
v0.18.0 URL検出を最適化します。これはより厳格であり、誤判断率を低下させます
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サポート
IPなどを介してURL検出をバイパスするユーザーは避けてください。これはデフォルトでは有効にされていません。
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 ());上記の機能はすべてデフォルトで有効になっており、ビジネスが関連する構成機能を柔軟に定義する必要がある場合があります。
したがって、v0.0.14はプロパティ構成を開きます。
よりエレガントに使用するために、この定義はFluent-APIによって均一に使用されます。
ユーザーはSensitiveWordBsを使用して次のように定義できます。
注:構成後、以前のツールメソッドではなく、新しく定義されたSensitiveWordBsオブジェクトを使用します。ツールメソッドの構成はすべてデフォルトです。
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 ));各構成の説明は次のとおりです。
| シリアルナンバー | 方法 | 説明します | デフォルト値 |
|---|---|---|---|
| 1 | Ignorecase | ケースを無視します | 真実 |
| 2 | 無視幅 | ハーフコーナーの丸い角を無視します | 真実 |
| 3 | Ignorenumstyle | 数字の執筆を無視します | 真実 |
| 4 | Chinesestyleを無視します | 中国語のライティング形式を無視します | 真実 |
| 5 | IngroreNglishStyle | 英語の執筆形式を無視します | 真実 |
| 6 | Ingorerepeat | 重複した単語を無視します | 間違い |
| 7 | enablenumcheck | デジタル検出を有効にするかどうか。 | 間違い |
| 8 | EnableMailCheck | 電子メールの検出が有効になっています | 間違い |
| 9 | enabableurcheck | リンク検出を有効にするかどうか | 間違い |
| 10 | enababeIpv4check | IPv4検出を有効にするかどうか | 間違い |
| 11 | enableWordCheck | 敏感な単語検出を有効にするかどうか | 真実 |
| 12 | Numchecklen | デジタル検出、指定された長さをカスタマイズします。 | 8 |
| 13 | wordtag | 対応する単語のタグ | なし |
| 14 | カリグノール | 無視された文字 | なし |
| 15 | WordResultCondition | 英語の単語の完全な一致の必要性を制限するなど、敏感な単語を一致させるための追加の処理 | 常に真です |
V0.16.1がサポートされています。時々、メモリを解放する必要がありますが、これは次のとおりです。
メモリリサイクルの問題について
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. init ();
// 后续因为一些原因移除了对应信息,希望释放内存。
wordBs . destroy ();使用法のシナリオ:初期化後、完全に再活性化するのではなく、単語を追加/削除する必要があります。この機能はこれに対応しています。
サポートバージョン:V0.19.0
addWord(word) 、単一の単語/コレクションをサポートし、敏感な単語を追加します
removeWord(word)敏感な単語を削除し、単一の単語/コレクションをサポートします
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 ());使用法のシナリオ:初期化後、完全に再活性化するのではなく、単語を追加/削除する必要があります。この機能はこれに対応しています。
サポートバージョン:V0.21.0
addWordAllow(word)新しいホワイトリストを追加し、単一の単語/コレクションをサポートします
removeWordAllow(word)ホワイトリストを削除し、単一の単語/コレクションをサポートします
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 ());この方法は放棄されます。上記の増分添加方法を使用して、全負荷を避けることをお勧めします。互換性のために、この方法は残ります。
使用方法: sensitiveWordBs.init()を呼び出すとき、iworddeny+iwordallowに基づいて敏感な語彙を再構築します。初期化には長い時間(第2レベル)がかかる可能性があるため、INITのすべての最適化は、完了していないときに古い語彙関数に影響を与えません。完了後、新しい語彙関数には影響しません。
@ Component
public class SensitiveWordService {
@ Autowired
private SensitiveWordBs sensitiveWordBs ;
/**
* 更新词库
*
* 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法。
* 如果需要生效,则调用这个方法。
*
* 说明:重新初始化不影响旧的方法使用。初始化完成后,会以新的为准。
*/
public void refresh () {
// 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法,然后调用这个方法。
sensitiveWordBs . init ();
}
}上記のように、 sensitiveWordBs.init();データベースレキシコンが変更され、データベースが有効になる必要がある場合。
他の用途は、アプリを再起動せずに同じままです。
サポートバージョン:V0.13.0
たとえば、一致する敏感な単語をさらに制限したい場合があります。たとえば、[av]を敏感な単語として定義しますが、[持っている]を一致させたくありません。
WordResultConditionインターフェイスをカスタマイズして、独自のポリシーを実装できます。
WordResultConditions#alwaysTrue()の組み込みポリシーは常に真であり、 WordResultConditions#englishWordMatch()では、英語が完全な単語と一致する必要があります。
WordResultConditionsツールクラスは、一致するポリシーを取得できます
| 成し遂げる | 説明します | サポートバージョン |
|---|---|---|
| 常に | 常に真です | |
| EnglishWordMatch | 英語の単語完全マッチング | v0.13.0 |
| EnglishWordNumMatch | 英語の単語/番号フルワードマッチング | V0.20.0 |
| ワードタグ | [広告]タグのみに焦点を当てるなど、特定のタグを満たすもの | V0.23.0 |
| チェーン(iWordResultCondition ...条件) | 複数の条件を指定し、同時に満たすことをサポートします | V0.23.0 |
元のデフォルトの状況:
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 ());英語が完全な単語と一致する必要があることを指定できます。
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 ());もちろん、必要に応じて、より複雑な戦略を実装できます。
サポートバージョン: v0.23.0
特定のラベルに関連する敏感な単語のみを返すことができます。
製品、av
mywordtagは、私たちが定義する敏感な単語タグ実装です。
/**
* 自定义单词标签
* @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 );
}
}たとえば、2つの異なる実装クラスをシミュレートし、それぞれが異なる単語タグに焦点を当てています。
// 只关心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 ());[愚かな帽子]など、私たちの敏感な言葉は一般的により連続しています
次に、[愚かなことです! @#$ hat]検出をスキップするために、しかし宣誓の攻撃力は減りません。
それでは、これらの同様のシナリオに対処する方法は?
特殊文字のスキップセットを指定し、これらの意味のないキャラクターを無視できます。
V0.11.0はサポートを開始します
Charignoreに対応するキャラクター戦略は、ユーザーが柔軟に定義できます。
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 ());時には、社会的状況、暴力などなど、敏感な言葉に分類されたラベルを追加したいと思うことがあります。
このようにして、特定のタイプのラベルのみを処理するなど、ラベルなどに従ってより多くの特性を実行できます。
サポートバージョン:V0.10.0
メイン機能サポートバージョン:V0.24.0
これは単なる抽象的なインターフェイスであり、ユーザーは自分で実装を定義できます。たとえば、データベースクエリ、ファイルの読み取り、API呼び出しなどから。
public interface IWordTag {
/**
* 查询标签列表
* @param word 脏词
* @return 结果
*/
Set < String > getTag ( String word );
}ほとんどの状況での使用を促進するために、 WordTagsクラスにいくつかのシーン戦略が実装されています
| 実装方法 | 説明します | 述べる |
|---|---|---|
| なし() | 空の実装 | V0.10.0サポート |
| file(stringfilepath) | ファイルパスを指定します | V0.10.0サポート |
| file(string filepath、string wordsplit、string tagsplit) | ファイルパスとワードセパレーターとタグセパレーターを指定します | V0.10.0サポート |
| マップ(最終マップ<文字列、set> wordtagmap) | MAPによる初期化 | V0.24.0サポート |
| 行(コレクションライン) | 文字列のリスト | V0.24.0サポート |
| 行(コレクションライン、文字列ワードスプリット、文字列タグスプリ) | 文字列のリスト、ワードセパレーターとラベルセパレーター | V0.24.0サポート |
| システム() | システムファイルの組み込み実装、ネットワーク分類の統合 | V0.24.0サポート |
| defaults() | デフォルトのポリシーは現在システムです | V0.24.0サポート |
| チェーン(iwordtag ...その他) | チェーンメソッドは、ユーザー統合をサポートして複数のポリシーを実装します | V0.24.0サポート |
デフォルトにデフォルトで次の敏感词tag1,tag2にデフォルトであるという敏感な単語タグの形式は、敏感词のタグがtag1とtag2であることを意味します。
例えば
五星红旗 政治,国家
これは、すべてのファイル行の内容と指定された文字列コンテンツにも推奨されます。満足していない場合は、カスタム方法で実装するだけです。
v0.24.0から始めて、デフォルトの単語タグはWordTags.system()です。
注:現在、データ統計はインターネットからのものであり、多くの省略があります。また、誰もが問題を修正し、改善し続けることを歓迎します...
SensitiveWordBs sensitiveWordBs = SensitiveWordBs . newInstance ()
. wordTag ( WordTags . system ())
. init ();
Set < String > tagSet = sensitiveWordBs . tags ( "博彩" );
Assert . assertEquals ( "[3]" , tagSet . toString ());ここで、圧縮サイズを最適化するために、対応するカテゴリは数字で表されます。
数字の意味リストは次のとおりです。
0 政治
1 毒品
2 色情
3 赌博
4 违法
ここでは、ファイルを例として使用して、使用方法を示します。
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 ());ここでdict_tag_test.txtカスタムコンテンツは次のとおりです。
零售 广告,网络
敏感な単語を取得すると、対応する結果処理戦略を設定して、対応する敏感な単語タグ情報を取得できます
// 自定义测试标签类
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 ());天安门キーワードのタグをカスタマイズし、Findallの結果処理戦略がWordResultHandlers.wordTags()であることを指定し、敏感な単語を取得しながら対応するタグリストを取得できます。
コンソールの変更など、敏感な単語のロードをダイナミックに設計し、リアルタイムで有効にすることがあります。
v0.0.13はこの機能をサポートしています。
この機能を実装し、以前の関数と互換性があるため、2つのインターフェイスを定義しました。
インターフェイスは次のとおりです。独自の実装をカスタマイズできます。
返されたリストは、単語が繊細な単語であることを意味します。
/**
* 拒绝出现的数据-返回的内容被当做是敏感词
* @author binbin.hou
* @since 0.0.13
*/
public interface IWordDeny {
/**
* 获取结果
* @return 结果
* @since 0.0.13
*/
List < String > deny ();
}例えば:
public class MyWordDeny implements IWordDeny {
@ Override
public List < String > deny () {
return Arrays . asList ( "我的自定义敏感词" );
}
}インターフェイスは次のとおりです。独自の実装をカスタマイズできます。
返されたリストは、単語が敏感な単語ではないことを意味します。
/**
* 允许的内容-返回的内容不被当做敏感词
* @author binbin.hou
* @since 0.0.13
*/
public interface IWordAllow {
/**
* 获取结果
* @return 结果
* @since 0.0.13
*/
List < String > allow ();
}のように:
public class MyWordAllow implements IWordAllow {
@ Override
public List < String > allow () {
return Arrays . asList ( "五星红旗" );
}
}もちろん、インターフェイスがカスタマイズされた後、有効にするために指定する必要があります。
よりエレガントに使用するために、ブートクラスのSensitiveWordBsを設計しました。
worddeny()を介して敏感な単語を指定することができます。wordallow()は非敏感な単語を指定し、init()を介して敏感な単語辞書を初期化できます。
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( WordDenys . defaults ())
. wordAllow ( WordAllows . defaults ())
. init ();
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( wordBs . contains ( text ));注:init()は、敏感な単語DFAを構築するのに時間がかかります。一般に、初期化を適用するときに1回のみ初期化することをお勧めします。初期化を繰り返す代わりに!
次のように、カスタム実装をテストできます。
String text = "这是一个测试,我的自定义敏感词。" ;
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( new MyWordDeny ())
. wordAllow ( new MyWordAllow ())
. init ();
Assert . assertEquals ( "[我的自定义敏感词]" , wordBs . findAll ( text ). toString ());これは我的自定义敏感词が敏感な単語であり、测试敏感な単語ではない唯一のものです。
もちろん、ここにすべてのカスタム実装があります。通常、システムのデフォルトの構成 +カスタム構成を使用することをお勧めします。
次の方法を使用できます。
WordDenys.chains()メソッドは、複数の実装を同じiworddenyにマージします。
WordAllows.chains()メソッドは、複数の実装を同じiwordallowにマージします。
例:
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 ());それらはすべて、システムのデフォルト構成とカスタム構成を同時に使用します。
注:新しいWordbsを初期化するため、新しいWordbsを使用して判断します。以前のSensitiveWordHelperツール法を使用する代わりに、ツールメソッドの構成がデフォルトです!
たとえば、実際に使用すると、ページ構成を変更してからリアルタイムで有効にすることができます。
データはデータベースに保存されます。以下は、擬似コードの例です。 SpringSensitiveWordConfig.javaを参照できます
必須、バージョンv0.0.15以上。
単純化された擬似コードは次のとおりであり、データのソースはデータベースです。
myddwordallowとmydddworddenyは、ソースとしてのデータベースに基づいたカスタム実装クラスです。
@ 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 ;
}
}敏感な語彙の初期化は時間がかかるため、プログラムの開始時に1回INIT初期化を行うことをお勧めします。
v0.6.0の後、対応するベンチマークテストを追加します。
Benchmarktimestest
テスト環境は通常のノートです:
处理器 12th Gen Intel(R) Core(TM) i7-1260P 2.10 GHz
机带 RAM 16.0 GB (15.7 GB 可用)
系统类型 64 位操作系统, 基于 x64 的处理器
PS:環境が異なりますが、割合は基本的に安定しています。
テストデータ:100以上の文字列、ループ10W回。
| シリアルナンバー | シーン | 時間がかかる | 述べる |
|---|---|---|---|
| 1 | フォーマット変換なしで敏感な単語のみを作成します | 1470ms、約7.2W QPS | 極端なパフォーマンスを追求すると、このように構成できます |
| 2 | 敏感な単語のみを作成し、すべてのフォーマット変換をサポートします | 2744ms、約3.7W QPS | ほとんどのシナリオを満たします |
個々の漢字から敏感な単語を削除します。中国では、フレーズは、誤判断率を減らすための単語と見なされるべきです。
個々の敏感な単語の変更をサポートしますか?
削除、追加、編集?
敏感な単語タグインターフェイスサポート
敏感な単語を処理するときのタグサポート
メモリ使用量の比較 +ワードダタの最適化
ユーザーはカスタムフレーズを指定し、指定されたフレーズの組み合わせを取得できるようにし、より柔軟になります
Formatcombine/CheckCombine/Allowdenycombineの組み合わせポリシー、ユーザーのカスタマイズが可能になります。
単語チェック戦略の最適化、統一されたトラバーサル +変換
threadlocalおよびその他のパフォーマンスの最適化を追加します
敏感なワード界面の敏感な単語コンソールv1.2.0オープンソース
敏感な単語admin v1.3.0リリースで分散展開をサポートする方法は?
01-オープンソースに敏感なワードツールの展望
02敏感な単語ツールを実装するために?禁止された言葉を実装するという考えを明確にします
03サポートワードストップワード停止単語最適化と特別なシンボル
04敏感な単語の控えめなゼロ
05敏感な単語のDFAアルゴリズムの05個の詳細な説明(Trie Treeアルゴリズム)
06感受性の単語(汚い言葉)意味のないキャラクターを無視する方法は?より良いフィルタリング効果を実現します
Dirty Word分類タグのV0.10.0-PRELIMINARINARサポート
v0.11.0-繊細な単語の新機能:無意味な文字、単語タグ辞書を無視する
V0.12.0に敏感な単語/汚いワードラベル付け能力がさらに強化されます
v0.13.0感受性単語機能バージョンリリースは、英語の単語で完全な単語マッチングをサポートしています
V0.16.1-Dictionaryメモリリソース敏感な単語の新機能のリリース
v0.19.0-敏感な単語の新機能を備えた繊細な単語が繰り返される初期化なしに個別に編集
v0.20.0敏感な単語の新しい特性は、部分的な一致ではなく、すべての数値と一致します
V0.21.0敏感な単語の新機能を備えたホワイトリストは、単一の編集をサポートし、ホワイトリストにブラックリストが含まれているときに問題を修正します
ピニインからピンイン
Pinyin2hanzi Pinyinから漢字へ
セグメント高性能中国語の単語セグメンテーション
opencc4j中国の伝統的な中国の簡略化された中国の変換
NLP-HANZI-類似の漢字の類似性
ワードチェッカースペル検出
敏感な言葉に敏感な言葉