你如何实现一个良好的亵渎过滤器?

问题描述 投票:194回答:21

我们中的许多人需要处理用户输入,搜索查询以及输入文本可能包含亵渎语言或不良语言的情况。通常需要将其过滤掉。

哪里可以找到各种语言和方言的咒骂词?

是否有可用于包含良好列表的源的API?或者也许一个API只是简单地说“是的这是干净的”或“没有这是脏的”一些参数?

有什么好方法可以让人们试图欺骗系统,比如$$,azz或a55?

如果您提供PHP解决方案,则可获得奖励积分。 :)

编辑:响应答案,只是避免程序问题:

例如,我认为这种过滤器有一个位置,例如,用户可以使用公共图像搜索来查找添加到敏感社区池的图片。如果他们可以搜索“阴茎”,那么他们很可能会得到许多照片,是的。如果我们不想要那些图片,那么防止这个词作为搜索词是一个很好的看门人,尽管不可否认这不是一个万无一失的方法。首先获取单词列表是真正的问题。

所以我真的指的是一种方法来弄清楚单个令牌是否脏,然后简单地禁止它。我不打算像完全搞笑的“长颈长颈鹿”参考那样阻止情绪。你无能为力。 :)

php regex user-input multilingual
21个回答
172
投票

Obscenity Filters: Bad Idea, or Incredibly Intercoursing Bad Idea?

此外,人们不能忘记The Untold History of Toontown's SpeedChat,甚至使用“安全词白名单”导致一个14岁的孩子迅速绕开它:“我想把我的长颈长颈鹿贴在蓬松的白色兔子身上。”

结论:最终,对于您实施的任何系统,绝对没有人类评论的替代品(无论是同行还是其他)。随意实现一个基本工具来摆脱驱动器,但对于确定的巨魔,你绝对必须有一个非基于算法的方法。

一个删除匿名并引入问责制的系统(Stack Overflow做得很好)也很有帮助,特别是为了帮助打击John Gabriel's G.I.F.T.

您还询问了哪些地方可以获得亵渎性列表以帮助您入门 - 一个要检查的开源项目是Dansguardian - 查看其默认亵渎列表的源代码。还有一个额外的第三方Phrase List,您可以下载代理,这可能是一个有用的收集点。

编辑以回答问题编辑:感谢您澄清您正在尝试做什么。在这种情况下,如果您只是尝试做一个简单的文字过滤器,有两种方法可以做到。一种是创建一个单一的长正则表达式,其中包含您要审查的所有禁用短语,并且仅使用它进行正则表达式查找/替换。像这样的正则表达式:

$filterRegex = "(boogers|snot|poop|shucks|argh)"

并使用preg_match()在输入字符串上运行它以批量测试命中,

或者preg_replace()将它们删除。

您还可以使用数组而不是单个长正则表达式加载这些函数,对于长单词列表,它可能更易于管理。有关如何灵活使用数组的一些好例子,请参阅preg_replace()

有关其他PHP编程示例,请参阅此页面以获取用于单词过滤的somewhat advanced generic class *来自删失单词的中心字母,此previous Stack Overflow question也有一个PHP示例(其中主要有价值的部分是基于SQL的过滤单词方法 - 如果您认为不必要,可以省去leet-speak补偿器。

您还补充说:“首先获取单词列表是真正的问题。” - 除了之前的一些Dansgaurdian链接,您可能会发现458个单词的this handy .zip很有帮助。


6
投票

如果您可以执行类似Digg / Stackoverflow的操作,用户可以在其中投票/标记淫秽内容......请执行此操作。

然后,您需要做的就是检查“顽皮”用户,如果他们违反规则就阻止他们。


4
投票

我参加派对有点晚了,但是我有一个解决方案可能适合那些阅读此内容的人。它是用javascript而不是php,但这是有正当理由的。

完全披露,我写了这个插件......

无论如何。

我采用的方法是允许用户“选择加入”他们的亵渎过滤。默认情况下,基本上会允许亵渎,但如果我的用户不想阅读它,他们就不必这样做。这也有助于解决“l33t sp3 @ k”问题。

这个概念是一个简单的插件,如果客户端的帐户启用了亵渎性过滤,它将被服务器注入。从那里,它只是几条简单的线条,抹去了发誓。

这是演示页面 https://chaseflorell.github.io/jQuery.ProfanityFilter/demo/

<div id="foo">
    ass will fail but password will not
</div>

<script>
    // code:
    $('#foo').profanityFilter({
        customSwears: ['ass']
    });
</script>

结果

***将失败,但密码不会


2
投票

别。它只会导致问题。我用亵渎过滤器获得的一个个人经验就是我从IRC频道被踢/被禁止的时间,因为我提到我“正在过桥到汉考克几个小时”或者其他类似的事情。


2
投票

我同意HanClinto在这次讨论中更高的帖子。我通常使用正则表达式来匹配输入文本。这是徒劳的,因为,就像你最初提到的那样,你必须在你的“被阻止”列表中明确地说明网上流行的每一种写作形式。

另外,在其他人正在辩论审查制度的道德规范时,我必须同意在网络上需要某种形式。有些人只是喜欢发表粗俗,因为它可以立即冒犯大量的人,并且绝对不需要作者的思考。

谢谢你的想法。

HanClinto规则!


2
投票

一旦你有一个很好的MYSQL表,你想要过滤一些坏词(我从这个帖子中的一个链接开始),你可以这样做:

$errors = array();  //Initialize error array (I use this with all my PHP form validations)

$SCREENNAME = mysql_real_escape_string($_POST['SCREENNAME']); //Escape the input data to prevent SQL injection when you query the profanity table.

$ProfanityCheckString = strtoupper($SCREENNAME); //Make the input string uppercase (so that 'BaDwOrD' is the same as 'BADWORD').  All your values in the profanity table will need to be UPPERCASE for this to work.

$ProfanityCheckString = preg_replace('/[_-]/','',$ProfanityCheckString); //I allow alphanumeric, underscores, and dashes...nothing else (I control this with PHP form validation).  Pull out non-alphanumeric characters so 'B-A-D-W-O-R-D' shows up as 'BADWORD'.

$ProfanityCheckString = preg_replace('/1/','I',$ProfanityCheckString); //Replace common numeric representations of letters so '84DW0RD' shows up as 'BADWORD'.

$ProfanityCheckString = preg_replace('/3/','E',$ProfanityCheckString);

$ProfanityCheckString = preg_replace('/4/','A',$ProfanityCheckString);

$ProfanityCheckString = preg_replace('/5/','S',$ProfanityCheckString);

$ProfanityCheckString = preg_replace('/6/','G',$ProfanityCheckString);

$ProfanityCheckString = preg_replace('/7/','T',$ProfanityCheckString);

$ProfanityCheckString = preg_replace('/8/','B',$ProfanityCheckString);

$ProfanityCheckString = preg_replace('/0/','O',$ProfanityCheckString); //Replace ZERO's with O's (Capital letter o's).

$ProfanityCheckString = preg_replace('/Z/','S',$ProfanityCheckString); //Replace Z's with S's, another common substitution.  Make sure you replace Z's with S's in your profanity database for this to work properly.  Same with all the numbers too--having S3X7 in your database won't work, since this code would render that string as 'SEXY'.  The profanity table should have the "rendered" version of the bad words.

$CheckProfanity = mysql_query("SELECT * FROM DATABASE.TABLE p WHERE p.WORD = '".$ProfanityCheckString."'");
if(mysql_num_rows($CheckProfanity) > 0) {$errors[] = 'Please select another Screen Name.';} //Check your profanity table for the scrubbed input.  You could get real crazy using LIKE and wildcards, but I only want a simple profanity filter.

if (count($errors) > 0) {foreach($errors as $error) {$errorString .= "<span class='PHPError'>$error</span><br /><br />";} echo $errorString;} //Echo any PHP errors that come out of the validation, including any profanity flagging.


//You can also use these lines to troubleshoot.
//echo $ProfanityCheckString;
//echo "<br />";
//echo mysql_error();
//echo "<br />";

我确信有一种更有效的方法来完成所有这些替换,但我不够聪明才能弄明白(这似乎工作正常,尽管效率低下)。

我相信你应该允许用户注册,并使用人来过滤并根据需要添加到你的亵渎表。虽然这一切都取决于假阳性的成本(好的词被标记为坏)而不是假阴性(坏词通过)。这应该最终决定你在过滤策略中的积极性或保守性。

如果你想使用通配符,我也会非常小心,因为它们有时会表现得比你想要的更加繁琐。


2
投票

我用12种语言收集了2200个坏词:en,ar,cs,da,de,eo,es,fa,fi,fr,hi,hu,it,ja,ko,nl,no,pl,pt,ru,sv ,th,tlh,tr,zh。

可以使用MySQL转储,JSON,XML或CSV选项。

https://github.com/turalus/openDB

我建议你在你的数据库中执行这个SQL,并在每次用户输入内容时进行检查。


1
投票

坦率地说,我会让他们得到“欺骗系统”的话,而禁止他们,这就是我。但它也使编程更简单。

我要做的是实现一个像这样的正则表达式过滤器:/[\s]dooby (doo?)[\s]/i或者它的前缀是/[\s]doob(er|ed|est)[\s]/。这些可以防止像过滤这样的过滤词,这是完全有效的,但是如果你学习了新的过滤器,还需要了解其他变体并更新实际的过滤器。显然这些都是例子,但你必须自己决定如何做。

我不打算输出我所知道的所有单词,而不是在我不想知道它们的时候。


1
投票

我同意这个主题是徒劳的,但如果你必须有一个过滤器,请查看Ning的Boxwood

Boxwood是一个PHP扩展,用于快速替换一段文本中的多个单词。它支持区分大小写和不区分大小写的匹配。它要求将其操作的文本编码为UTF-8。

另请参阅此博客文章了解更多详情:

使用Boxwood,您可以根据需要设置搜索词列表 - 搜索和替换算法不会因为要查找的单词列表中的更多单词而变慢。它的工作原理是构建所有搜索词的trie,然后只扫描一次主题文本,沿着trie的元素向下走,并将它们与文本中的字符进行比较。它支持US-ASCII和UTF-8,区分大小写或不区分大小写,并且具有一些以英语为中心的单词边界检查逻辑。


1
投票

我总结道,为了创建一个好的亵渎过滤器,我们需要3个主要组件,或者至少它是我要做的。这些是:

  1. 过滤器:后台服务,用于验证黑名单,字典或类似内容。
  2. 不允许匿名帐户
  3. 报告滥用

奖金,它将以某种方式奖励那些为准确的滥用记者做出贡献并惩罚犯罪者的人,例如:暂停他们的帐户。


0
投票

在比赛的后期,但做了一些研究,偶然发现了这里。正如其他人所提到的,如果它是自动化的几乎几乎是不可能的,但如果你的设计/要求可能涉及某些情况(但不是所有时间)人类的互动以审查它是否是亵渎,你可以考虑ML。 https://docs.microsoft.com/en-us/azure/cognitive-services/content-moderator/text-moderation-api#profanity现在是我目前的选择,原因有多种:

  • 支持许多本地化
  • 他们不断更新数据库,所以我不必跟上最新的俚语或语言(维护问题)
  • 如果概率很高(即90%或更高),你可以用实际的方式否认它
  • 您可以观察导致可能会或可能不会亵渎的旗帜的类别,并且可以让某人审查它以教导它是否是亵渎。

根据我的需要,它是基于公众友好的商业服务(OK,视频游戏),其他用户可能/将看到用户名,但设计要求必须通过亵渎过滤器来拒绝令人反感的用户名。关于这一点的可悲部分是经典的“clbuttic”问题很可能会发生,因为用户名通常是单个单词(最多N个字符),有时多个单词连接起来......再次,Microsoft的认知服务不会将“Assist”标记为Text。 HasProfanity = true但可能标记其中一个类别概率为高。

正如OP询问的那样,“a $$”,这是我通过过滤器时的结果:enter image description here,正如你所看到的,它已经确定它不是亵渎,但它很有可能是,所以标志为审查(人类互动)的建议。

当概率很高时,我可以退回“我很抱歉,这个名字已被采取”(即使它不是),这样对于反审查人员或其他东西,如果我们不想要整合人工评论,或者返回“您的用户名已通知实际运营部门,您可以等待您的用户名被审核和批准,或者选择其他用户名”。管他呢...

顺便说一下,这个服务的成本/价格对我来说是非常低的(用户名多久更改一次?),但同样,OP可能设计需要更密集的查询,可能不是理想的支付/订阅ML服务,或者不能进行人工审查/互动。这一切都取决于设计...但如果设计确实符合要求,也许这可能是OP的解决方案。

如果有兴趣,我可以在将来的评论中列出缺点。


39
投票

虽然我知道这个问题相当陈旧,但这是一个常见问题......

亵渎过滤器有一个原因和明显的需要(参见Wikipedia entry here),但由于非常不同的原因,它们通常不能100%准确;背景和准确性。

它(完全)取决于你想要实现的目标 - 在最基本的情况下,你可能试图覆盖“seven dirty words”然后一些......一些企业需要过滤最基本的亵渎:基本的咒骂词,URL或甚至个人信息等,但其他人需要防止非法帐户命名(Xbox live就是一个例子)或更多...

用户生成的内容不仅包含潜在的脏话,还可能包含令人反感的引用:

  • 性行为
  • 性取向
  • 宗教
  • 种族
  • 等等...

可能还有多种语言。迄今为止,Shutterstock已开发出10种语言的basic dirty-words lists,但它仍然是基本的,并且非常注重其“标记”需求。网上还有许多其他列表。

我同意接受的答案,即它不是一门定义的科学,语言是一个不断发展的挑战,但90%的捕获率优于0%。这完全取决于你的目标 - 你想要达到的目标,你所拥有的支持程度以及删除不同类型亵渎的重要性。

在构建过滤器时,您需要考虑以下元素以及它们与项目的关系:

  • 词/短语
  • 缩略语(FOAD / LMFAO等)
  • False positives(单词,地点和名称,如'mishit','scunthorpe'和'titsworth')
  • 网址(色情网站是明显的目标)
  • 个人信息(电子邮件,地址,电话等 - 如果适用)
  • 语言选择(默认情况下通常为英语)
  • 审核(如果有的话,您可以如何与用户生成的内容进行交互以及您可以使用它做什么)

你可以轻松地建立一个亵渎过滤器,捕获90%以上的亵渎,但你永远不会达到100%。这是不可能的。你越接近100%,它就变得越难......过去构建了一个复杂的亵渎引擎,每天处理超过500K的实时消息,我会提供以下建议:

基本过滤器包括:

  • 建立适用的亵渎名单
  • 开发一种处理亵渎衍生的方法

中等复杂的文件管理器将涉及(除了基本过滤器):

  • 使用复杂模式匹配来处理扩展派生(使用高级正则表达式)
  • 处理Leetspeak(l33t)
  • 处理false positives

复杂的过滤器将涉及以下许多(除了中等过滤器):


-2
投票

别。

因为:

  • Clbuttic
  • 亵渎不是OMG EVIL
  • 亵渎无法有效定义
  • 大多数人很可能不喜欢受到“亵渎”的保护

编辑:虽然我同意评论者说“审查是错误的”,但这不是这个答案的本质。


-2
投票

亵渎过滤器是一个坏主意。原因是你无法抓住每一个发誓的话。如果你尝试,你会得到误报。

抓住话语

我们只想说你要抓住F-Word。容易,对吗?好的,我们等着瞧。

你可以循环一个字符串来找到“他妈的”。不幸的是,人们现在使用过滤器。亵渎过滤器没有拿起“fuk”。

可以尝试检查单词的多个拼写和变体,但这会降低代码的性能。要捕捉F-Word,你需要寻找“fuc”,“fuc”,“fuk”,“Fuk”,“F ***”等等。然后列表会继续下去。

避免无罪

那么,如何使它不区分大小写并忽略空格,以便它捕获“F u C k”?这可能听起来不错,但有人可以用“F.U.C.K”绕过亵渎过滤器。

你忽略了标点符号。

现在这是一个真正的问题,因为像“你好,那里!”这样的句子。会选择“地狱”和“Whassup?”拿起来作为“屁股”。

你必须从过滤器中排除许多单词,例如“宪法”,因为其中有“标题”。

人们也可以使用替代词,例如“弗拉克”。你也阻止了吗? “阴茎”的“笔是什么”?你的程序没有人工智能来知道字符串是好还是坏。

不要使用亵渎过滤器。它们难以开发,而且它们像爬行一样慢。


26
投票

我不知道有什么好的图书馆,但无论你做什么,都要确保你犯错误的方向。我处理的系统不允许我使用“mpassell”作为用户名,因为它包含“ass”作为子字符串。这是疏远用户的好方法!


23
投票

在我的面试中,正在采访我的公司CTO试用了我用Java编写的单词/网页游戏。在整个牛津英语词典的单词列表中,第一个出现在猜测的词是什么?

当然,英语中最肮脏的词。

不知何故,我仍然得到了工作机会,但我随后追踪了一个亵渎词汇表(不是unlike this one),并编写了一个快速脚本来生成一个没有所有坏词的新词典(甚至不需要查看列表)。

对于您的特定情况,我认为将搜索与真实单词进行比较听起来像是使用类似单词列表的方式。替代样式/标点符号需要更多的工作,但我怀疑用户会经常使用它成为一个问题。


21
投票

亵渎过滤系统永远不会是完美的,即使程序员是自信并且随时了解所有裸体发展

也就是说,任何“顽皮词汇”的列表都可能与其他列表一样好,因为潜在的问题是语言理解,这对于当前的技术来说几乎是难以理解的

所以,唯一可行的解​​决方案是双重的:

  1. 准备好经常更新你的字典
  2. 聘请人工编辑来纠正误报(例如“clbuttic”而不是“classic”)和假阴性(哎呀!错过了一个!)


13
投票

防止攻击性用户输入的唯一方法是阻止所有用户输入。

如果您坚持允许用户输入并需要审核,那么请合并人工审核人。


7
投票

关于你的“欺骗系统”子问题,你可以通过在搜索之前规范化“坏词”列表和用户输入的文本来处理这个问题。例如,使用一系列正则表达式(或者如果PHP有,则使用tr)将[z $ 5]转换为“s”,[4 @]转换为“a”等,然后将规范化的“坏词”列表与规范化列表进行比较文本。请注意,规范化可能会导致额外的误报,尽管我现在无法想到任何实际情况。

更大的挑战是提出一些让人们在阻止“e s”时引用“钢笔比剑更强大”的东西。


7
投票

谨防本地化问题:在一种语言中,什么是脏话可能在另一种语言中是一个完全正常的词。

目前的一个例子是:ebay使用字典方法从反馈中过滤“坏词”。如果您尝试输入“这是一个完美的交易”(“das war eine perfekte Transaktion”)的德语翻译,ebay将拒绝由于不良词汇的反馈。

为什么?因为“是”的德语单词是“战争”,而“战争”是在“坏词”的ebay词典中。

所以要注意本地化问题。

© www.soinside.com 2019 - 2024. All rights reserved.