Merge branch 'server' into 'master'
BE-API 최종구현 ## BACKEND API 최종구현 - calcDistance 구현 ( 넘어온 word에 대해서 1. 원본/ 2. 특수기호, 영어, 숫자 제거 / 3. 특수기호, 영어, 숫자 표준화 각각의 disassenbled 된 단어들로 db 욕설들과 유사도 검사 => 최소 값 검증) See merge request !2
Showing
7 changed files
with
129 additions
and
40 deletions
server/controller/calcDistance.js
0 → 100644
| 1 | + | ||
| 2 | +const e = require('express'); | ||
| 3 | +const levenshtein = require('js-levenshtein'); | ||
| 4 | +const db = require('../model/db'); | ||
| 5 | +const {calcDistance} = require('../service/calcDistance'); | ||
| 6 | +const {getProfanity} = require('../service/query'); | ||
| 7 | +const {standardize, removeSpecial} = require('../service/standardization'); | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +exports.calcDistance = async (req, res, next) => { | ||
| 11 | + const { word } = req.body; | ||
| 12 | + | ||
| 13 | + const profanityList = await getProfanity(); | ||
| 14 | + | ||
| 15 | + let specialRemoved = removeSpecial(word); | ||
| 16 | + let specialNotRemoved = word; | ||
| 17 | + | ||
| 18 | + specialRemoved = standardize(specialRemoved); | ||
| 19 | + specialNotRemoved = standardize(specialNotRemoved); | ||
| 20 | + | ||
| 21 | + const rareResult = calcDistance(word, profanityList); | ||
| 22 | + const specialRemovedResult = calcDistance(specialRemoved, profanityList); | ||
| 23 | + const specialNotRemovedResult = calcDistance(specialNotRemoved, profanityList); | ||
| 24 | + | ||
| 25 | + const minResult = Math.min(rareResult, specialRemovedResult, specialNotRemovedResult); | ||
| 26 | + | ||
| 27 | + if (minResult <= 1){ | ||
| 28 | + res.status(200).json({success : true, isProfanity : "YES"}); | ||
| 29 | + }else{ | ||
| 30 | + res.status(200).json({success : true, isProfanity : "NO"}); | ||
| 31 | + } | ||
| 32 | + }; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -2,16 +2,15 @@ const mysql = require('mysql2/promise'); | ... | @@ -2,16 +2,15 @@ const mysql = require('mysql2/promise'); |
| 2 | const dotenv = require('dotenv'); | 2 | const dotenv = require('dotenv'); |
| 3 | const path = require('path'); | 3 | const path = require('path'); |
| 4 | 4 | ||
| 5 | -dotenv.config({path:path.join(__dirname, "../.env")}); | 5 | +dotenv.config({ path: path.join(__dirname, '../.env') }); |
| 6 | 6 | ||
| 7 | -const db = mysql | 7 | +const db = mysql.createPool({ |
| 8 | - .createPool({ | 8 | + host: process.env.DB_HOST, |
| 9 | - host: process.env.DB_HOST, | 9 | + user: process.env.DB_USER, |
| 10 | - user: process.env.DB_USER, | 10 | + port: process.env.DB_PORT, |
| 11 | - port: process.env.DB_PORT, | 11 | + password: process.env.DB_PASSWORD, |
| 12 | - password: process.env.DB_PASSWORD, | 12 | + database: process.env.DB_DATABASE, |
| 13 | - database: process.env.DB_DATABASE, | 13 | + connectionLimit: 10, |
| 14 | - connectionLimit: 10, | 14 | +}); |
| 15 | - }); | ||
| 16 | 15 | ||
| 17 | module.exports = db; | 16 | module.exports = db; | ... | ... |
| ... | @@ -14,6 +14,7 @@ | ... | @@ -14,6 +14,7 @@ |
| 14 | "hangul-js": "^0.2.6", | 14 | "hangul-js": "^0.2.6", |
| 15 | "http-errors": "~1.6.3", | 15 | "http-errors": "~1.6.3", |
| 16 | "jade": "~1.11.0", | 16 | "jade": "~1.11.0", |
| 17 | + "js-levenshtein": "^1.1.6", | ||
| 17 | "morgan": "~1.9.1", | 18 | "morgan": "~1.9.1", |
| 18 | "mysql2": "^2.2.5" | 19 | "mysql2": "^2.2.5" |
| 19 | }, | 20 | }, | ... | ... |
| ... | @@ -2,9 +2,9 @@ const express = require('express'); | ... | @@ -2,9 +2,9 @@ const express = require('express'); |
| 2 | 2 | ||
| 3 | const router = express.Router(); | 3 | const router = express.Router(); |
| 4 | 4 | ||
| 5 | +const { calcDistance } = require('../controller/calcDistance'); | ||
| 6 | + | ||
| 5 | /* GET home page. */ | 7 | /* GET home page. */ |
| 6 | -router.post('/checkProfanity', (req, res) => { | 8 | +router.post('/checkProfanity', calcDistance); |
| 7 | - res.send('hello'); | ||
| 8 | -}); | ||
| 9 | 9 | ||
| 10 | module.exports = router; | 10 | module.exports = router; | ... | ... |
| 1 | +/* eslint-disable no-restricted-syntax */ | ||
| 2 | +const levenshtein = require('js-levenshtein'); | ||
| 3 | +const Hangul = require('hangul-js'); | ||
| 4 | + | ||
| 5 | +exports.calcDistance = (word, profanityList) => { | ||
| 6 | + let leastLevenshtein = 1000; | ||
| 7 | + | ||
| 8 | + for (const profanity of profanityList[0]) { | ||
| 9 | + let compareWord = Hangul.disassemble(profanity.content); | ||
| 10 | + compareWord = compareWord.join(''); | ||
| 11 | + if (leastLevenshtein > levenshtein(word, compareWord)) { | ||
| 12 | + leastLevenshtein = levenshtein(word, compareWord); | ||
| 13 | + } | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + return leastLevenshtein; | ||
| 17 | +}; | ... | ... |
server/service/query.js
0 → 100644
| 1 | /* eslint-disable no-use-before-define */ | 1 | /* eslint-disable no-use-before-define */ |
| 2 | /* eslint-disable no-restricted-syntax */ | 2 | /* eslint-disable no-restricted-syntax */ |
| 3 | +const { config } = require('dotenv'); | ||
| 3 | const Hangul = require('hangul-js'); | 4 | const Hangul = require('hangul-js'); |
| 4 | 5 | ||
| 5 | const standardize = (word) => { | 6 | const standardize = (word) => { |
| ... | @@ -12,7 +13,7 @@ const standardize = (word) => { | ... | @@ -12,7 +13,7 @@ const standardize = (word) => { |
| 12 | ? standardizeConsonent(letter) | 13 | ? standardizeConsonent(letter) |
| 13 | : standardizeVowel(letter); | 14 | : standardizeVowel(letter); |
| 14 | } else { | 15 | } else { |
| 15 | - const preLetter = index === 1 ? '' : disassembledWord[index - 1]; | 16 | + const preLetter = index === 0 ? '' : disassembledWord[index - 1]; |
| 16 | const nextLetter = index === disassembledWord.length - 1 ? '' : disassembledWord[index + 1]; | 17 | const nextLetter = index === disassembledWord.length - 1 ? '' : disassembledWord[index + 1]; |
| 17 | newLetter = isVowelSpecial(preLetter, letter, nextLetter) | 18 | newLetter = isVowelSpecial(preLetter, letter, nextLetter) |
| 18 | ? standardizeSpecialVowel(letter) | 19 | ? standardizeSpecialVowel(letter) |
| ... | @@ -92,40 +93,72 @@ const isVowelSpecial = (preLetter, letter, nextLetter) => { | ... | @@ -92,40 +93,72 @@ const isVowelSpecial = (preLetter, letter, nextLetter) => { |
| 92 | 93 | ||
| 93 | const standardizeSpecialConsonent = (letter) => { | 94 | const standardizeSpecialConsonent = (letter) => { |
| 94 | switch (letter) { | 95 | switch (letter) { |
| 95 | - case ('g', 'ㅑ'): | 96 | + case ('g', 'k', 'G', 'K'): |
| 96 | - return 'ㅏ'; | 97 | + return 'ㄱ'; |
| 97 | - case ('ㅗ', 'ㅛ'): | 98 | + case ('b', 'v', 'B', 'V'): |
| 98 | - return 'ㅗ'; | 99 | + return 'ㅂ'; |
| 99 | - case ('ㅐ', 'ㅒ', 'ㅔ', 'ㅖ', 'ㅙ', 'ㅚ', 'ㅝ', 'ㅞ'): | 100 | + case ('P', 'p', 'F', 'f'): |
| 100 | - return 'ㅐ'; | 101 | + return 'ㅍ'; |
| 101 | - case ('ㅜ', 'ㅠ'): | 102 | + case ('n', 'L', 'N'): |
| 102 | - return 'ㅜ'; | 103 | + return 'ㄴ'; |
| 103 | - case ('ㅓ', 'ㅕ'): | 104 | + case ('s', 'A', 'S', 'C', 'c'): |
| 104 | - return 'ㅓ'; | 105 | + return 'ㅅ'; |
| 105 | - case ('ㅟ', 'ㅢ', 'ㅣ'): | 106 | + case ('d', 't', 'E'): |
| 106 | - return 'ㅣ'; | 107 | + return 'ㄷ'; |
| 108 | + case ('o', 'O'): | ||
| 109 | + return 'ㅇ'; | ||
| 110 | + case ('r', 'R'): | ||
| 111 | + return 'ㄹ'; | ||
| 112 | + case ('j', 'z', 'J', 'Z'): | ||
| 113 | + return 'ㅈ'; | ||
| 114 | + case ('m', '口', 'M'): | ||
| 115 | + return 'ㅁ'; | ||
| 116 | + case ('h', 'H'): | ||
| 117 | + return 'ㅎ'; | ||
| 107 | default: | 118 | default: |
| 108 | return letter; | 119 | return letter; |
| 109 | } | 120 | } |
| 110 | }; | 121 | }; |
| 111 | 122 | ||
| 112 | const standardizeSpecialVowel = (letter) => { | 123 | const standardizeSpecialVowel = (letter) => { |
| 124 | + let result = ''; | ||
| 125 | + | ||
| 113 | switch (letter) { | 126 | switch (letter) { |
| 114 | - case ('g', 'ㅑ'): | 127 | + case ('a', 'A'): |
| 115 | - return 'ㅏ'; | 128 | + result = 'ㅏ'; |
| 116 | - case ('ㅗ', 'ㅛ'): | 129 | + break; |
| 117 | - return 'ㅗ'; | 130 | + case ('u', 'U'): |
| 118 | - case ('ㅐ', 'ㅒ', 'ㅔ', 'ㅖ', 'ㅙ', 'ㅚ', 'ㅝ', 'ㅞ'): | 131 | + result = 'ㅓ'; |
| 119 | - return 'ㅐ'; | 132 | + break; |
| 120 | - case ('ㅜ', 'ㅠ'): | 133 | + case ('@', 'H'): |
| 121 | - return 'ㅜ'; | 134 | + result = 'ㅐ'; |
| 122 | - case ('ㅓ', 'ㅕ'): | 135 | + break; |
| 123 | - return 'ㅓ'; | 136 | + case ('l', 'i', 'I', '!', 1): |
| 124 | - case ('ㅟ', 'ㅢ', 'ㅣ'): | 137 | + result = 'ㅣ'; |
| 125 | - return 'ㅣ'; | 138 | + break; |
| 139 | + case '1': | ||
| 140 | + result = 'ㅣ'; | ||
| 141 | + break; | ||
| 126 | default: | 142 | default: |
| 127 | - return letter; | 143 | + result = letter; |
| 144 | + break; | ||
| 128 | } | 145 | } |
| 146 | + | ||
| 147 | + return result; | ||
| 148 | +}; | ||
| 149 | + | ||
| 150 | +const removeSpecial = (word) => { | ||
| 151 | + const numCheck = /[0-9]/g; // 숫자 | ||
| 152 | + | ||
| 153 | + const engCheck = /[a-zA-Z]/g; // 문자 | ||
| 154 | + | ||
| 155 | + const specialCheck = /[~!@#$%^&*()_+|<>?:{}]/g; // 특수문자 | ||
| 156 | + | ||
| 157 | + let result = word.replace(numCheck, ''); | ||
| 158 | + result = result.replace(engCheck, ''); | ||
| 159 | + result = result.replace(specialCheck, ''); | ||
| 160 | + | ||
| 161 | + return result; | ||
| 129 | }; | 162 | }; |
| 130 | 163 | ||
| 131 | -module.exports = { standardize }; | 164 | +module.exports = { standardize, removeSpecial }; | ... | ... |
-
Please register or login to post a comment