Чувствительное слово-это высокопроизводительный чувствительный инструмент Word, основанный на алгоритме DFA.
Онлайн -опыт
Если у вас есть трудные и сложные заболевания, вы можете присоединиться: группа технической обмена
Чувствительное слово-админ является соответствующим применением консоли. Функции в настоящее время находятся на ранних стадиях разработки, и версия MVP доступна.
Всем привет, я Лао Ма.
Я всегда хотел реализовать простой и простой в использовании конфиденциальное инструмент Word, поэтому я реализовал этот инструмент с открытым исходным кодом.
Основываясь на реализации алгоритма DFA, содержание конфиденциального тезауруса в настоящее время включает 6W+ (исходный файл 18W+, после одного удаления).
На более поздней стадии чувствительный тезаурус будет непрерывно оптимизирован и дополнен, а производительность алгоритма будет дополнительно улучшена.
V0.24.0 начал поддерживать классификацию и уточнение чувствительных слов, но рабочая нагрузка относительно большая, поэтому неизбежно упущения.
Добро пожаловать в PR улучшения, GitHub запросы или присоединиться к группе технического обмена, чтобы общаться и хвастаться!
6W+ тезаурус, а также непрерывная оптимизация и обновление
Основываясь на реализации Fluent-API, элегантном и кратком использовании
На основе алгоритма DFA производительность составляет 7 Вт+ QP, приложение нечувствительное
Поддерживать общие операции, такие как суждение, возврат и десенсибилизация конфиденциальных слов
Поддерживает общее преобразование формата
Полночечная полота с половиной ширины, английский обмен, общие формы чисел, традиционные китайские и упрощенные китайские, общие формы английского обмена, игнорирование дублирующих слов и т. Д.
Поддержка конфиденциального обнаружения слов, обнаружение электронной почты, цифровое обнаружение, обнаружение веб -сайта, IPv4 и т. Д.
Поддерживает пользовательские политики замены
Поддерживает пользовательские чувствительные слова и белые списки
Поддерживает динамические обновления данных (настройка пользователя), эффективно в режиме реального времени
Поддерживает интерфейс тегов + встроенная реализация классификации для конфиденциальных слов
Поддержка пропуска некоторых специальных персонажей, чтобы сделать соответствие более гибким
Поддерживает единственное добавление/модификацию черно -белых списков без полной инициализации
Change_log.md
Иногда существует консоль для конфиденциальных слов, которая делает ее более гибким и удобным для настройки.
Как реализовать консольную консольную службу Word из коробки?
Было отсортировано большое количество конфиденциальных файлов тегов Word, что может сделать наши конфиденциальные слова более удобными.
Эти два материала можно прочитать в статье ниже:
v0.11.0 Новые функции конфиденциальных слов и соответствующих файлов тегов
В настоящее время v0.24.0 имеет встроенные теги Word, и рекомендуется перейти на последнюю версию, если это необходимо.
Открытый исходный код не просто. Если этот проект полезен для вас, вы можете пригласить Lao Ma принять чашку молочного чая.

JDK1.8+
Maven 3.x+
< dependency >
< groupId >com.github.houbb</ groupId >
< artifactId >sensitive-word</ artifactId >
< version >0.24.0</ version >
</ dependency > SensitiveWordHelper - это класс инструментов для чувствительных слов. Основные методы заключаются в следующем:
Примечание. SensitiveWordHelper предоставляет конфигурации по умолчанию. Если вы хотите создать гибкие пользовательские конфигурации, обратитесь к конфигурации функции класса загрузки
| метод | параметр | Возвращаемое значение | иллюстрировать |
|---|---|---|---|
| содержит (строка) | Строка, которая должна быть проверена | Логическая ценность | Убедитесь, что строка содержит чувствительные слова |
| Заменить (строка, iSensityWordReplace) | Заменить конфиденциальные слова на указанную стратегию замены | Нить | Возвращает десенсибилизированную строку |
| заменить (строка, char) | Используйте указанный символ, чтобы заменить чувствительное слово | Нить | Возвращает десенсибилизированную строку |
| Заменить (строка) | Используйте * , чтобы заменить чувствительные слова | Нить | Возвращает десенсибилизированную строку |
| Findall (String) | Строка, которая должна быть проверена | Список струн | Возвращает все чувствительные слова в строке |
| FindFirst (String) | Строка, которая должна быть проверена | Нить | Возвращает первое конфиденциальное слово в строке |
| Findall (String, iWordResulthandler) | IwordResulthandler Result Class | Список струн | Возвращает все чувствительные слова в строке |
| FindFirst (String, iWordResulthandler) | IwordResulthandler Result Class | Нить | Возвращает первое конфиденциальное слово в строке |
| теги (строка) | Получите теги для чувствительных слов | Чувствительная строка слова | Вернуться в список тегов для конфиденциальных слов |
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 поддерживает эту функцию.
Описание сцены: Иногда мы хотим, чтобы разные чувствительные слова имели разные результаты замены. Например, [Game] заменяется [E-Sports], а [безработица] заменяется [гибкой занятостью].
По общему признанию, можно заранее использовать регулярную замену строк, но производительность средняя.
Пример использования:
/**
* 自定替换策略
* @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 Поддержка
Избегайте пользователей обходить обнаружение URL с помощью IP и т. Д., Который не включен по умолчанию.
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 | Негрифейс | Игнорировать дело | истинный |
| 2 | Игнорировать | Игнорировать полукоры округленных углов | истинный |
| 3 | Игноринумстил | Игнорировать написание чисел | истинный |
| 4 | Игнорировать Chinesestyle | Игнорировать китайский формат письма | истинный |
| 5 | Игнорировать | Игнорировать формат написания английского языка | истинный |
| 6 | Негриболевание | Игнорировать дублирующие слова | ЛОЖЬ |
| 7 | EnablenumCheck | Чтобы включить цифровое обнаружение. | ЛОЖЬ |
| 8 | Enablemailcheck | Обнаружение электронной почты включено | ЛОЖЬ |
| 9 | Включить | Чтобы включить обнаружение ссылок | ЛОЖЬ |
| 10 | enableipv4check | Включить обнаружение 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+I WrivestAllow. Поскольку инициализация может занять много времени (второй уровень), все оптимизации для INIT не повлияют на старую словару, когда она не будет завершена, а новый должен преобладать после завершения .
@ Component
public class SensitiveWordService {
@ Autowired
private SensitiveWordBs sensitiveWordBs ;
/**
* 更新词库
*
* 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法。
* 如果需要生效,则调用这个方法。
*
* 说明:重新初始化不影响旧的方法使用。初始化完成后,会以新的为准。
*/
public void refresh () {
// 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法,然后调用这个方法。
sensitiveWordBs . init ();
}
} Как упомянуто выше, вы можете активно запустить инициализацию sensitiveWordBs.init(); Когда лексика базы данных меняется, и база данных должна вступить в силу.
Другие использование остаются прежними без перезапуска приложения.
Поддерживаемая версия: v0.13.0
Иногда, например, мы можем еще больше ограничить сопоставление чувствительных слов, хотя мы определяем [AV] как чувствительное слово, мы не хотим, чтобы [имели] соответствовать.
Вы можете настроить интерфейс WordesultCondition и реализовать свои собственные политики.
Встроенная политика в WordResultConditions#alwaysTrue() всегда верна, в то время как WordResultConditions#englishWordMatch() требует, чтобы английский язык соответствовал полному слову.
Класс инструментов WordesultConditions может получить политику сопоставления
| выполнить | иллюстрировать | Поддерживаемая версия |
|---|---|---|
| Всегда | Всегда верно | |
| EnglishwordMatch | Английское слово полное сопоставление слова | v0.13.0 |
| EnglishWordNummatch | Английское слово/номер Полное сопоставление слов | v0.20.0 |
| WordTags | Те, которые удовлетворяют конкретные теги, такие как сосредоточение внимания только на тегах [рекламы] | 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 );
}
}Например, мы имитируем два разных класса реализации, каждый из которых фокусируется на различной теге слова.
// 只关心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], чтобы пропустить обнаружение, но сила атаки ругательства не уменьшается.
Итак, как справиться с этими подобными сценариями?
Мы можем указать наборы Skip специальных символов и игнорировать эти бессмысленные символы.
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 Поддержка |
| Файл (строка FilePath) | Укажите путь к файлу | V0.10.0 Поддержка |
| File (String filePath, String WordsPlit, String TagsPlit) | Укажите пути файлов, а также разделители слов и сепараторы тегов | V0.10.0 Поддержка |
| Карта (окончательная карта <string, set> wordtagmap) | Инициализация в соответствии с картой | V0.24.0 Поддержка |
| Линии (линии сбора) | Список струн | V0.24.0 Поддержка |
| Строки (строки коллекции, строковые слова, строковые теги) | Список строк, а также разделители слов и сепараторы маркировки | V0.24.0 Поддержка |
| система() | Встроенная реализация системных файлов, интеграция сетевой классификации | V0.24.0 Поддержка |
| по умолчанию () | Политика по умолчанию в настоящее время является системой | 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 поддерживает эту функцию.
Чтобы реализовать эту функцию и быть совместимым с предыдущими функциями, мы определили два интерфейса.
Интерфейс заключается в следующем, вы можете настроить свою собственную реализацию.
Возвращенный список означает, что слово является конфиденциальным словом.
/**
* 拒绝出现的数据-返回的内容被当做是敏感词
* @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 к классу загрузочного класса.
Вы можете указать конфиденциальные слова через WordDyy (), WordAllow () указывает нечувствительные слова и инициализируя словарь чувствительных слов через init ().
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( WordDenys . defaults ())
. wordAllow ( WordAllows . defaults ())
. init ();
final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。" ;
Assert . assertTrue ( wordBs . contains ( text ));Примечание: init () занимает много времени, чтобы построить чувствительное слово DFA. Обычно рекомендуется инициализировать только один раз при применении инициализации. Вместо повторяющейся инициализации!
Мы можем проверить пользовательскую реализацию следующим образом:
String text = "这是一个测试,我的自定义敏感词。" ;
SensitiveWordBs wordBs = SensitiveWordBs . newInstance ()
. wordDeny ( new MyWordDeny ())
. wordAllow ( new MyWordAllow ())
. init ();
Assert . assertEquals ( "[我的自定义敏感词]" , wordBs . findAll ( text ). toString ()); Вот единственный, где我的自定义敏感词являются чувствительными словами, а测试не являются чувствительными словами.
Конечно, вот все наши пользовательские реализации. Обычно рекомендуется использовать конфигурацию по умолчанию + пользовательскую конфигурацию системы.
Следующий метод может быть использован.
Метод WordDenys.chains() объединяет несколько реализаций в одну и ту же iworddeny.
Метод WordAllows.chains() объединяет несколько реализаций в одну и ту же iReadlowlak.
пример:
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 и выше.
Упрощенный псевдокод выглядит следующим образом, и источником данных является база данных.
MyDd WriptionAllow и MyDdWordDeny - это пользовательские классы реализации, основанные на базах данных в качестве источника.
@ 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 ;
}
}Инициализация чувствительного словаря требует много времени, поэтому рекомендуется выполнять инициализацию инициализации инициализации один раз, когда программа запускается.
После v0.6.0 добавьте соответствующий тест на эталон.
Benchmartimestest
Тестовая среда - это обычная ноутбука:
处理器 12th Gen Intel(R) Core(TM) i7-1260P 2.10 GHz
机带 RAM 16.0 GB (15.7 GB 可用)
系统类型 64 位操作系统, 基于 x64 的处理器
PS: разные среды будут различаться, но пропорция в основном стабильна.
Данные тестирования: 100+ строки, петля 10 Вт.
| Серийный номер | Сцена | кропотливый | Примечание |
|---|---|---|---|
| 1 | Сделайте только чувствительные слова без какого -либо преобразования формата | 1470 мс, около 7,2 Вт QP | Следуя экстремальной производительности, вы можете настроить ее так |
| 2 | Сделайте только чувствительные слова, поддерживайте все преобразование формата | 2744 мс, около 3,7 Вт QP | Встретить большинство сценариев |
Удалите чувствительные слова из отдельных китайских иероглиф. В Китае фразы следует рассматривать как одно слово, чтобы снизить скорость неправильного суждения.
Поддерживает отдельные чувствительные изменения слова?
Удалить, добавить, редактировать?
Поддержка конфиденциального интерфейса тега Word
Поддержка тегов при обработке чувствительных слов
Сравнение использования памяти + оптимизация WordData
Пользователи указывают пользовательские фразы и позволяют получить комбинацию указанных фраз, делая их более гибкими
Formatcombine/CheckCombine/AllucdenyCombine Комбинированная политика, позволяющая пользовательской настройке.
Оптимизация стратегии проверки слов, объединенное обход + конверсия
Добавить Threadlocal и другие оптимизации производительности
чувствительное слово-админ чувствительное слово консоль v1.2.0 с открытым исходным кодом
Как поддержать распределенное развертывание в выпуске чувствительного слова v1.3.0?
01-Beginner с открытым исходным костюмом инструмент Word
02-как для реализации конфиденциального инструмента Word? Уточнить идею реализации запрещенных слов
03-поддержка Стоп слов Стоп Стоп Оптимизация слов и специальные символы
04-Dictionary чувствительных слов похудение
05 Detailed Объяснение алгоритма DFA чувствительных слов (алгоритм Trie Tree)
06-чувствительные слова (грязные слова) Как игнорировать бессмысленные символы? Достичь лучшего эффекта фильтрации
V0.10.0-предварительная поддержка тега классификации грязного слова
v0.11.0 - Новые функции чувствительных слов: игнорируйте бессмысленные символы, словарь тегов слов
v0.12.0 чувствительная к слову/грязному словам
v0.13.0-чувствительная версия функции Word поддерживает полное сопоставление слов по английским словам
v0.16.1 Двеянная память Выпуск ресурсов памяти новых функций конфиденциальных слов
v0.19.0 - чувствительные слова с новыми особенностями конфиденциальных слов, отредактированных без повторной инициализации
v0.20.0 Новые характеристики чувствительных слов соответствуют всем числам, а не частичным совпадениям
v0.21.0 Белые списки с новыми функциями конфиденциальных слов поддерживают отдельное редактирование, исправляя проблему, когда белые списки содержат черные списки
пинин до пинеина
pinyin2hanzi pinyin для китайских иерог
Сегмент высокопроизводительный сегментация китайского слова
opencc4j китайский традиционный китайский упрощенный китайский обращение
NLP-Hanzi-Simvalling китайское сходство именем
Обнаружение орфографии
Чувствительные слова чувствительные слова