장준영

Merge branch 'server' into 'master'

BE-API 최종구현

## BACKEND API 최종구현

- calcDistance 구현  
 ( 넘어온 word에 대해서 1. 원본/  2. 특수기호, 영어, 숫자 제거 / 3. 특수기호, 영어, 숫자 표준화  
각각의 disassenbled 된 단어들로 db 욕설들과 유사도 검사 => 최소 값 검증)

See merge request !2
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 +};
......
1 +const db = require('../model/db');
2 +
3 +exports.getProfanity = async () => {
4 + const selectResult = await db.query("SELECT DISTINCT content from profanity");
5 +
6 + return selectResult;
7 +};
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 };
......