![]() |
Mikey Wilson, 2002 |
檢測髒話
首先,讓我們試著判斷一個句子是否含有任何髒話。注意中文與英文的判斷方式略有不同,底下將分開討論。
檢測中文髒話
對於中文,我們的目標是從一個完整的句子當中,找出是否有特定的髒話關鍵字。以 javascript 來講,我們可以使用 String 的 indexOf() 方法,判斷某一字串是否含有另外一個字串。範例程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var chineseList = ["笨", "胖", "王八"]; var isProfane = function(string){ for (var i = 0; i < chineseList.length; i++) { if (string.indexOf(chineseList[i]) > -1) { return true; } } return false; }; var string1 = "王老先生有八塊地"; var string2 = "你媽超胖,她的肚臍比她早十五分鐘到家"; console.log(isProfane(string1)); // false console.log(isProfane(string2)); // true |
String.indexOf 方法會在一個字串中搜尋另一個字串的所在位置。如果找不到,則會回傳 -1 。因此判斷中文髒話的方法,就是列出所有你要搜尋的髒話,然後逐一放到 indexOf 中去搜尋。只要有任何一個關鍵字出現,就可以認定此字串中含有髒話。
檢測英文髒話
英文的判斷方法就不同了。因為英文單字是由多個字母組成,有時候一個髒話單字可能被包含在另一個正常的單字當中。比方說, assassin 這個單字雖然含有髒話 ass,但我們並不應該把 assassin 當成髒話。
所以,判斷英文髒話必須以單字為單位做比對,髒話跟比較對象的單字必須要完全相等才行。我們可以用下面的程式碼,先將句子拆解成單字後,再逐一與髒話列表做全文比對:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var englishList = ["ass", "bitch", "cunt"]; var isProfane = function(string){ var words = string.split(" "); for (var i = 0; i < words.length; i++) { var word = words[i].toLowerCase(); if (englishList.indexOf(word) > -1) { return true; } } return false; }; var string1 = "We work in the dark to serve the light. We are assassins."; var string2 = "I'm CEO, Bitch"; console.log(isProfane(string1)); // false console.log(isProfane(string2)); // true |
在上面的程式碼中,我們先把字串以空白分割成單字,存在陣列 words 當中。再使用 Array.indexOf 方法,判斷單字是否在髒話列表陣列當中。這跟前面用的 String.indexOf 不一樣,它是在陣列中找完全相同的元素,所以可以用來做我們需要的全文比對。
髒話消音
另一個常用的功能是只把句子中的髒話部分消除,或是替換成其他符號,保留其餘部分的文字。底下一樣展示中文與英文的不同做法。
我們可以很簡單的用 javascript 原生的 String.replace 方法,把髒話部分替換掉即可。程式碼範例如下:
要過濾的句子先進入到 clean 函式中,會先用與前面相同的檢測方式,判斷句子中是否含有中文髒話。如果有,句子會進入 replaceWord 函式進行處理。
在 replaceWord 函式中,我們先建立一個跟原先髒話相同長度,僅由星號 * 所組成的字串。最後呼叫 string.replace 來將句子中的髒話以星號字串取代掉。由於同一句髒話可能在一個句子中出現不只一次,因此在 replace 中的正規表達式要加上 g 這參數,確保整個句子都會被比對一遍。
中文髒話消音
我們可以很簡單的用 javascript 原生的 String.replace 方法,把髒話部分替換掉即可。程式碼範例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var chineseList = ["笨", "胖", "王八"]; var placeHolder = "*"; var replaceWord = function(string, target){ var t = ""; for(var i = 0; i < target.length; i++){ t += placeHolder; } return string.replace(new RegExp(target, 'g'), t); }; var clean = function(string){ for (var i = 0; i < chineseList.length; i++) { if (string.indexOf(chineseList[i]) > -1) { string = replaceWord(string, chineseList[i]); } } return string; }; var string1 = "你媽超胖,她的肚臍比她早十五分鐘到家"; var string2 = "你王八蛋,你們全家都王八蛋"; console.log(clean(string1)); // 你媽超*,她的肚臍比她早十五分鐘到家 console.log(clean(string2)); // 你**蛋,你們全家都**蛋 |
要過濾的句子先進入到 clean 函式中,會先用與前面相同的檢測方式,判斷句子中是否含有中文髒話。如果有,句子會進入 replaceWord 函式進行處理。
在 replaceWord 函式中,我們先建立一個跟原先髒話相同長度,僅由星號 * 所組成的字串。最後呼叫 string.replace 來將句子中的髒話以星號字串取代掉。由於同一句髒話可能在一個句子中出現不只一次,因此在 replace 中的正規表達式要加上 g 這參數,確保整個句子都會被比對一遍。
英文髒話消音
比對英文時,還是要先把句子拆開成多個單字,再逐一比對。範例程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | var englishList = ["ass", "bitch", "cunt"]; var placeHolder = "*"; var cleanWord = function(word){ var t = ""; for(var i = 0; i < word.length; i++){ t += placeHolder; } return t; }; var clean = function(){ var words = string.split(" "); for (i = 0; i < words.length; i++) { var word = words[i].toLowerCase(); if (englishList.indexOf(word) > -1) { words[i] = cleanWord(words[i]); } } return words.join(' '); }; var string1 = "We work in the dark to serve the light. We are assassins."; var string2 = "I'm CEO, Bitch"; console.log(clean(string1)); // We work in the dark to serve the light. We are assassins. console.log(clean(string2)); // I'm CEO, ***** |
要過濾的句子先進入到 clean 函式中,會先用與前面相同的方式,把句子拆開成多個單字,再逐一判斷此單字是否為英文髒話。如果是,單字會進入 cleanWord 函式進行處理。
在 cleanWord 函式中,我們建立一個跟原先髒話相同長度,僅由星號 * 所組成的字串,就直接回傳,取代原先單字。
最後,我們把所有被拆解開的單字,利用 Array.join 方法,重新組回一個句子即可。
變種
前面的中文髒話判斷方式有一個比較明顯的缺點,在於它無法分辨以標點、空白或特殊字元分開的髒話。比方說,「王八蛋」是一個髒話,但「王 八 蛋」就無法被判斷成髒話。如果想要連這樣的字串都檢測出來,可以先用 String.replace 方法,把所有不是中文字的符號從句子中移除:
正規表達式 /[^\u4e00-\u9fff]/g 會比對所有不是中文的字母或符號,然後 String.replace 就會把它們以空字串取代,也就是刪除的意思,這樣句子中的空白就全部消失了。
英文也可以如法炮製,把英文字母、數字以外的符號都先移除。可以使用 /[^a-zA-Z0-9]/g 做為正規表達式。
不過,這種方法比較難以用在消音的功能上面,畢竟它會破壞掉原本句子中的符號,而且就算檢測到髒話,也不容易找出要消音的範圍。我建議如果要在聊天室使用這類的變種,不如就不做消音了,改成一旦偵測到髒話就將整句移除或禁止發言,較為省事。
本文介紹了我在 Node.js 環境中實做中英文髒話偵測與過濾的方法。藉由 javascript 的幾種原生方法,我們可以很容易的做出髒話過濾器,並得以將它用在聊天室等各種應用程式中。
整份程式碼可以到我的 GitHub 觀看,之後應該會將它打包發布到 npm 上。有任何疑問、建議或希望增加的髒話,也歡迎隨時在上面提出。
2016年2月1日:
此 Module 已發布到 npm 上,請到 https://www.npmjs.com/package/bad-words-chinese 上觀看使用說明。
bad-words, by webmech 一個英文的髒話過濾模組。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var chineseList = ["笨", "胖", "王八蛋"]; var isProfane = function(string){ for (var i = 0; i < chineseList.length; i++) { if (string.indexOf(chineseList[i]) > -1) { return true; } } return false; }; var string = "你 這 王 八 蛋"; console.log(isProfane(string)); // false console.log(isProfane(string.replace(/[^\u4e00-\u9fff]/g, ""))); // true |
正規表達式 /[^\u4e00-\u9fff]/g 會比對所有不是中文的字母或符號,然後 String.replace 就會把它們以空字串取代,也就是刪除的意思,這樣句子中的空白就全部消失了。
英文也可以如法炮製,把英文字母、數字以外的符號都先移除。可以使用 /[^a-zA-Z0-9]/g 做為正規表達式。
不過,這種方法比較難以用在消音的功能上面,畢竟它會破壞掉原本句子中的符號,而且就算檢測到髒話,也不容易找出要消音的範圍。我建議如果要在聊天室使用這類的變種,不如就不做消音了,改成一旦偵測到髒話就將整句移除或禁止發言,較為省事。
結論
本文介紹了我在 Node.js 環境中實做中英文髒話偵測與過濾的方法。藉由 javascript 的幾種原生方法,我們可以很容易的做出髒話過濾器,並得以將它用在聊天室等各種應用程式中。
整份程式碼可以到我的 GitHub 觀看,之後應該會將它打包發布到 npm 上。有任何疑問、建議或希望增加的髒話,也歡迎隨時在上面提出。
2016年2月1日:
此 Module 已發布到 npm 上,請到 https://www.npmjs.com/package/bad-words-chinese 上觀看使用說明。
參考資料
bad-words, by webmech 一個英文的髒話過濾模組。
沒有留言:
張貼留言