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

在哪里可以找到各种语言和方言的粗口?

源代码中是否有包含好的列表的api ?或者可能是一个API,用一些参数简单地说“是的,这是干净的”或“不,这是脏的”?

有什么好方法可以捕捉那些试图欺骗系统的人,比如$$、azz或a55?

如果您为PHP提供了解决方案,则会有加分。:)

编辑:回答简单地说,避免程序问题:

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

我指的是一种方法来判断单个令牌是否脏,然后简单地禁止它。我不会费心去阻止那种完全滑稽的“长脖子长颈鹿”的说法。你在那里什么也做不了。:)


当前回答

我同意这个主题的徒劳,但如果你必须有一个过滤器,看看宁泽涛的黄杨木:

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

更多细节请参见这篇博客文章:

快速多字符串替换PHP

使用Boxwood,你可以让你的搜索词列表想多长就多长——搜索和替换算法不会因为单词列表上有更多的单词而变慢。它的工作原理是建立一个包含所有搜索词的三元组,然后只扫描你的主题文本一次,遍历三元组中的元素,并将它们与文本中的字符进行比较。它支持US-ASCII和UTF-8,区分大小写或不敏感的匹配,并具有一些以英语为中心的单词边界检查逻辑。

其他回答

淫秽过滤器:坏主意,还是令人难以置信的坏主意?

此外,我们不能忘记Toontown的SpeedChat的不被人知的历史,在那里,即使使用“安全词白名单”,也会导致一个14岁的孩子迅速绕过它: “我想把我的长脖子长颈鹿插到你毛茸茸的白兔子身上。”

底线:最终,对于您实现的任何系统,绝对没有什么可以替代人工评审(无论是同行评审还是其他评审)。你可以随意使用一个基本的工具来消除这种恶意攻击,但对于那些顽固的恶意攻击者,你绝对必须使用一种非基于算法的方法。

一个消除匿名并引入问责制的系统(Stack Overflow在这方面做得很好)也很有帮助,特别是为了帮助对抗约翰·加布里埃尔的G.I.F.T.

你还问你从哪里可以得到亵渎列表来开始你的学习——一个开源项目是Dansguardian——看看他们默认的亵渎列表的源代码。还有一个额外的第三方短语列表,你可以为代理下载,这可能是一个有用的收集点。

编辑:谢谢你对你想要做的事情的澄清。在这种情况下,如果你只是想做一个简单的单词过滤器,有两种方法可以做到。一种方法是创建一个单独的长regexp,其中包含您想要审查的所有禁用短语,并使用它进行regex查找/替换。像这样的正则表达式:

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

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

或preg_replace()来清空它们。

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

有关其他PHP编程示例,请参阅本页,其中有一个比较高级的用于单词过滤的泛型类,它从经过审查的单词中删除了中间的字母,以及前面的Stack Overflow问题,其中也有一个PHP示例(其中主要有价值的部分是基于sql的过滤单词方法——如果您发现它不必要,可以省去let -speak补偿器)。

你还补充说:“真正的问题是首先获得单词列表。”——除了之前的一些丹斯格尔链接,你可能会发现这个458个单词的。zip很有用。

一旦你有了一个好的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 />";

我确信有一种更有效的方法来完成所有这些替换,但我不够聪明,无法找到它(尽管效率不高,但这似乎还可以)。

我认为你应该允许用户注册,并根据需要使用人工过滤和添加到你的亵渎表。尽管这一切都取决于一个假阳性(好的词被标记为坏)和一个假阴性(坏词通过)的成本。这将最终决定您在过滤策略中是积极还是保守。

如果您想使用通配符,我也会非常小心,因为它们有时会比您想要的更麻烦。

我不知道有什么好的库可以做到这一点,但无论你做什么,都要确保你在让东西通过的方向上犯了错误。我曾经遇到过不允许我使用“mpassell”作为用户名的系统,因为它包含“ass”作为子字符串。这是一种疏远用户的好方法!

我同意hanclininto在讨论中发表的文章。我通常使用正则表达式来匹配输入文本。这是徒劳的努力,就像你最初提到的那样,你必须明确地在你的“阻止”列表中解释网络上流行的每一种写作技巧。

另一方面,当其他人在讨论审查的道德问题时,我必须同意在网络上有某种形式是必要的。有些人只是喜欢发表粗俗的文章,因为它可以立即冒犯到很多人,而且作者完全不需要思考。

谢谢你的建议。

HanClinto规则!

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

更大的挑战是想出一种方法,让人们在引用“笔比剑更强大”的同时屏蔽“pen is”。