溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python基于DFA算法怎么實現(xiàn)內(nèi)容敏感詞過濾

發(fā)布時間:2022-04-22 10:03:48 來源:億速云 閱讀:205 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“Python基于DFA算法怎么實現(xiàn)內(nèi)容敏感詞過濾”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python基于DFA算法怎么實現(xiàn)內(nèi)容敏感詞過濾”吧!

DFA 算法是通過提前構(gòu)造出一個 樹狀查找結(jié)構(gòu),之后根據(jù)輸入在該樹狀結(jié)構(gòu)中就可以進行非常高效的查找。

設(shè)我們有一個敏感詞庫,詞酷中的詞匯為:

  • 我愛你

  • 我愛他

  • 我愛她

  • 我愛你呀

  • 我愛他呀

  • 我愛她呀

  • 我愛她啊

那么就可以構(gòu)造出這樣的樹狀結(jié)構(gòu):

設(shè)玩家輸入的字符串為:白菊我愛你呀哈哈哈

我們遍歷玩家輸入的字符串 str,并設(shè)指針 i 指向樹狀結(jié)構(gòu)的根節(jié)點,即最左邊的空白節(jié)點:

  • str[0] = ‘白’ 時,此時 tree[i] 沒有指向值為 ‘白’ 的節(jié)點,所以不滿足匹配條件,繼續(xù)往下遍歷

  • str[1] = ‘菊’,同樣不滿足匹配條件,繼續(xù)遍歷

  • str[2] = ‘我’,此時 tree[i] 有一條路徑連接著 ‘我’ 這個節(jié)點,滿足匹配條件,i 指向 ‘我’ 這個節(jié)點,然后繼續(xù)遍歷

  • str[3] = ‘愛’,此時 tree[i] 有一條路徑連著 ‘愛’ 這個節(jié)點,滿足匹配條件,i 指向 ‘愛’,繼續(xù)遍歷

  • str[4] = ‘你’,同樣有路徑,i 指向 ‘你’,繼續(xù)遍歷

  • str[5] = ‘呀’,同樣有路徑,i 指向 ‘呀’

此時,我們的指針 i 已經(jīng)指向了樹狀結(jié)構(gòu)的末尾,即此時已經(jīng)完成了一次敏感詞判斷。我們可以用變量來記錄下這次敏感詞匹配開始時玩家輸入字符串的下標,和匹配結(jié)束時的下標,然后再遍歷一次將字符替換為 * 即可。

結(jié)束一次匹配后,我們把指針 i 重新指向樹狀結(jié)構(gòu)的根節(jié)點處。

此時我們玩家輸入的字符串還沒有遍歷到頭,所以繼續(xù)遍歷:

str[6] = ‘哈’,不滿足匹配條件,繼續(xù)遍歷

str[7] = ‘哈’ …

str[8] = ‘哈’ …

可以看出我們遍歷了一次玩家輸入的字符串,就找到了其中的敏感詞匯。

Python基于DFA算法怎么實現(xiàn)內(nèi)容敏感詞過濾

DFA算法python實現(xiàn)

class DFA:
    """DFA 算法
       敏感字中“*”代表任意一個字符
    """

    def __init__(self, sensitive_words: list, skip_words: list):  # 對于敏感詞sensitive_words及無意義的詞skip_words可以通過數(shù)據(jù)庫、文件或者其他存儲介質(zhì)進行保存
        self.state_event_dict = self._generate_state_event(sensitive_words)
        self.skip_words = skip_words

    def __repr__(self):
        return '{}'.format(self.state_event_dict)

    @staticmethod
    def _generate_state_event(sensitive_words) -> dict:
        state_event_dict = {}
        for word in sensitive_words:
            tmp_dict = state_event_dict
            length = len(word)
            for index, char in enumerate(word):
                if char not in tmp_dict:
                    next_dict = {'is_end': False}
                    tmp_dict[char] = next_dict
                    tmp_dict = next_dict
                else:
                    next_dict = tmp_dict[char]
                    tmp_dict = next_dict
                if index == length - 1:
                    tmp_dict['is_end'] = True
        return state_event_dict

    def match(self, content: str):
        match_list = []
        state_list = []
        temp_match_list = []

        for char_pos, char in enumerate(content):
            if char in self.skip_words:
                continue
            if char in self.state_event_dict:
                state_list.append(self.state_event_dict)
                temp_match_list.append({
                    "start": char_pos,
                    "match": ""
                })
            for index, state in enumerate(state_list):
                is_match = False
                state_char = None
                if '*' in state: # 對于一些敏感詞,比如大傻X,可能是大傻B,大傻×,大傻...,采用通配符*,一個*代表一個字符
                    state_list[index] = state['*']
                    state_char = state['*']
                    is_match = True
                if char in state:
                    state_list[index] = state[char]
                    state_char = state[char]
                    is_match = True
                if is_match:
                    if state_char["is_end"]:
                        stop = char_pos + 1
                        temp_match_list[index]['match'] = content[
                                                          temp_match_list[index]['start']:stop]
                        match_list.append(copy.deepcopy(temp_match_list[index]))
                        if len(state_char.keys()) == 1:
                            state_list.pop(index)
                            temp_match_list.pop(index)
                else:
                    state_list.pop(index)
                    temp_match_list.pop(index)
        for index, match_words in enumerate(match_list):
            print(match_words['start'])
        return match_list

_generate_state_event方法生成敏感詞的樹狀結(jié)構(gòu),(以字典保存),對于上面的例子,生成的樹狀結(jié)構(gòu)保存如下:

if __name__ == '__main__':
    dfa = DFA(['我愛你', '我愛他', '我愛她', '我愛你呀', '我愛他呀', '我愛她呀', '我愛她啊'], skip_words=[])  # 暫時不配置skip_words
    print(dfa)

結(jié)果:

{'我': {'is_end': False, '愛': {'is_end': False, '你': {'is_end': True, '呀': {'is_end': True}}, '他': {'is_end': True, '呀': {'is_end': True}}, '她': {'is_end': True, '呀': {'is_end': True}, '啊': {'is_end': True}}}}}

然后調(diào)用match方法,輸入內(nèi)容進行敏感詞匹配:

if __name__ == '__main__':
    dfa = DFA(['我愛你', '我愛他', '我愛她', '我愛你呀', '我愛他呀', '我愛她呀', '我愛她啊'], ['\n', '\r\n', '\r'])
    # print(dfa)
    print(dfa.match('白菊我愛你呀哈哈哈'))

結(jié)果:

[{'start': 2, 'match': '我愛你'}, {'start': 2, 'match': '我愛你呀'}]

而對于一些敏感詞,比如大傻X,可能是大傻B,大傻×,大傻...,那是不是可以通過一個通配符*來解決?

見代碼:48 ~51行

if '*' in state: # 對于一些敏感詞,比如大傻X,可能是大傻B,大傻×,大傻...,采用通配符*,一個*代表一個字符
 state_list[index] = state['*']
 state_char = state['*']
 is_match = True

驗證一下:

if __name__ == '__main__':
    dfa = DFA(['大傻*'], [])
    print(dfa)
    print(dfa.match('大傻X安樂飛大傻B'))

{'大': {'is_end': False, '傻': {'is_end': False, '*': {'is_end': True}}}}
[{'start': 0, 'match': '大傻X'}, {'start': 6, 'match': '大傻B'}]

上列中如果輸入的內(nèi)容中,“大傻X安樂飛大傻B”寫成“大%傻X安樂飛大&傻B”,看看是否能識別出敏感詞呢?識別不出了!

if __name__ == '__main__':
    dfa = DFA(['大傻*'], [])
    print(dfa)
    print(dfa.match('大%傻X安樂飛大&傻B'))

結(jié)果:

{'大': {'is_end': False, '傻': {'is_end': False, '*': {'is_end': True}}}}
[

諸如“,&,!,!,@,#,$,¥,*,^,%,?,?,<,>,《,》",這些特殊符號無實際意義,但是可以在敏感詞中間插入而破壞敏感詞的結(jié)構(gòu)規(guī)避敏感詞檢查

進行無意義詞配置,再進行敏感詞檢查,如下,可見對于被破壞的敏感詞也能識別

if __name__ == '__main__':
    dfa = DFA(['大傻*'], ['%', '&'])
    print(dfa)
    print(dfa.match('大%傻X安樂飛大&傻B'))

結(jié)果: 

{'大': {'is_end': False, '傻': {'is_end': False, '*': {'is_end': True}}}}
[{'start': 0, 'match': '大%傻X'}, {'start': 7, 'match': '大&傻B'}]

感謝各位的閱讀,以上就是“Python基于DFA算法怎么實現(xiàn)內(nèi)容敏感詞過濾”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Python基于DFA算法怎么實現(xiàn)內(nèi)容敏感詞過濾這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI