簡體   English   中英

PHP篩選禁止單詞的文本

[英]PHP Filter text for banned words

我們有一個C2C網站,我們不鼓勵在我們的網站上銷售品牌產品。 我們建立了一個品牌詞匯數據庫,如NikeD&G,並制作了一個算法來過濾這些詞的產品信息,並禁用產品,如果它包含這些詞。

我們當前的算法從提供的文本中刪除所有空格和特殊字符,並將文本與數據庫中的單詞匹配。 這些情況需要通過算法捕獲並有效捕獲:

  • 我是世界的
  • 我有n個鞋子
  • 我有nikeeshoes
  • 我賣i-phone外殼
  • 我賣iphone-casing
  • 你可以有iphone

現在的問題是它還包含以下內容:

  • rapiD服裝廠(D&G)
  • rosNIK Electronics(耐克)

如何在捕獲真實案例的同時保持效率,可以采取哪些措施來防止這種錯誤匹配?

編輯

以下是那些更了解代碼的人的代碼:

$orignal_txt = preg_replace('/&.{0,}?;/', '', (strip_tags($orignal_txt)));
$orignal_txt_nospace = preg_replace('/\W/', '', $orignal_txt);
{
    $qry_kws = array("nike", "iphone", "d&g");
    foreach($qry_kws as $rs_kw)
    {       
        $no_space_db_kw = preg_replace('/\W/', '', $rs_kw);
        if(stristr($orignal_txt_nospace, $rs_kw))
        {
            $ipr_banned_keywords[] = strtolower($rs_kw);
        }
        else if(stristr($orignal_txt_nospace, $no_space_db_kw))
        {
                $ipr_banned_keywords[] = strtolower($rs_kw);
        }

    }
}

只是玩....(不用於生產)

$data = array(
        "i am nike world",
        "i have n ikee shoes",
        "i have nikeeshoes",
        "i sell i-phone casings",
        "i sell iphone-casings",
        "you can have iphone",
        "rapiD Garment factor",
        "rosNIK Electronics",
        "Buy you self N I K E",
        "B*U*Y I*P*H*O*N*E BABY",
        "My Phone Is not available");


$ban = array("nike","d&g","iphone");

例1:

$filter = new BrandFilterIterator($data);
$filter->parseBan($ban);
foreach ( $filter as $word ) {
    echo $word, PHP_EOL;
}

輸出1

rapiD Garment factor
rosNIK Electronics
My Phone Is not available

例2

$filter = new BrandFilterIterator($data,true); //reverse filter
$filter->parseBan($ban);
foreach ( $filter as $word ) {
    echo $word, " " , json_encode($word->getBan()) ,  PHP_EOL;
}

輸出2

i am nike world ["nike"]
i have n ikee shoes ["nike"]
i have nikeeshoes ["nike"]
i sell i-phone casings ["iphone"]
i sell iphone-casings ["iphone"]
you can have iphone ["iphone"]
Buy you self N I K E ["nike"]
B*U*Y I*P*H*O*N*E BABY ["iphone"]

使用的類

class BrandFilterIterator extends FilterIterator {
    private $words = array();
    private $reverse = false;

    function __construct(array $words, $reverse = false) {
        $this->reverse = $reverse;
        foreach ( $words as $word ) {
            $this->words[] = new Word($word);
        }
        parent::__construct(new ArrayIterator($this->words));
    }

    function parseBan(array $ban) {
        foreach ( $ban as $item ) {
            foreach ( $this->words as $word ) {
                $word->checkMetrix($item);
            }
        }
    }

    public function accept() {
        if ($this->reverse) {
            return $this->getInnerIterator()->current()->accept() ? false : true;
        }
        return $this->getInnerIterator()->current()->accept();
    }
}


class Word {
    private $ban = array();
    private $word;
    private $parts;
    private $accept = true;

    function __construct($word) {
        $this->word = $word;
        $this->parts = explode(" ", $word);
    }

    function __toString() {
        return $this->word;
    }

    function getTrim() {
        return preg_replace('/\W/', '', $this->word);
    }

    function accept() {
        return $this->accept;
    }

    function getBan() {
        return array_unique($this->ban);
    }

    function reject($ban = null) {
        $ban === null or $this->ban[] = $ban;
        $this->accept = false;
        return $this->accept;
    }

    function checkMetrix($ban) {
        foreach ( $this->parts as $part ) {
            $part = strtolower($part);
            $ban = strtolower($ban);
            $t = ceil(strlen(strtolower($ban)) / strlen($part) * 100);
            $s = similar_text($part, $ban, $p);
            $l = levenshtein($part, $part);
            if (ceil($p) >= $t || ($t == 100 && $p >= 75 && $l == 0)) {
                $this->reject($ban);
            }
        }
        // Detect Bad Use of space
        if (ceil(strlen($this->getTrim()) / strlen($this->word) * 100) < 75) {
            if (stripos($this->getTrim(), $ban) !== false) {
                $this->reject($ban);
            }
        }
        return $this->accept;
    }
}

很簡單,在刪除空格/特殊字符之前進行品牌匹配。 然后它將不匹配這些奇怪的邊緣情況。

你已經知道了這一點,但值得明確說明:你當前的算法完全不適合這項任務。 它甚至不能處理簡單的情況,更不用說人們故意試圖通過你的過濾器的情況了。 你可以用你當前的過濾器做一件事,那就完全扔掉了 - 它無法發揮作用。

雖然我們在這里沒有討論一個obsenity過濾器,但它幾乎是同一種概念,因此建議您閱讀由obsenity過濾器產生的一些最嚴重的錯誤。

這些文章主要涉及誤報 - 即過濾器對不應該的東西進行匹配,從而阻止合法的條目。 這種事情可能會非常具有破壞性,因為它會讓您的客戶感到不安,如果它發生了很多,它會讓人們遠離您的網站。 自然語言的復雜性幾乎是不可避免的。

您還需要了解假陰性。 這些是您的過濾器無法獲取應該拾取的東西的地方。 你的問題在於垃圾郵件制造者擁有大量的技術來獲取過濾器。 您當前的過濾器很容易過去,但即使是最先進的過濾器也可能會失敗 - 請檢查您收件箱中收到多少垃圾郵件以獲取此類證據。 而且他們一直在改變他們的技術,所以靜態算法根本不會長期發揮作用。

貝葉斯過濾器似乎是最適合您的解決方案。 這些過濾器可以隨時學習。 您需要密切關注它們並培訓它們以識別需要過濾的內容,因此設置起來會有一些工作,但我懷疑您是否會以任何其他方式提供可行的解決方案。

這只是一個想法。

為什么不首先進行匹配,如果它遇到“品牌”過濾器,它會被放入審核隊列中供您接受/拒絕,突出顯示匹配以便於發現。

人類將能夠發現幾乎是立即和准確地使用品牌。 你甚至可以把它變成機器學習,誰知道:)

話雖如此,這不是一個正則表達式問題,並不能通過漂亮的表達來解決; 系統需要訓練,記住命中(增加信心)並從未命中中學習。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM