vanila javascript 개선된 초성검색 기능 구현
이전에 포스팅한 초성검색은, 단순 한글 초성 검색을 했을 경우 값을 조회하는 기능였습니다.
Link : aljjabaegi.tistory.com/219
Link : aljjabaegi.tistory.com/220
여기에 MariaDB 기준으로 개선된 초성 검색 기능을 구현해 보려고 합니다.
우선 초성을 추출하는 MariaDB 함수는 초성과 공백을 리턴하도록 수정되었습니다. (기존에는 초성만 추출)
CREATE DEFINER=`CITSARCH`@`%` FUNCTION `FNC_NTCN`(
`str` VARCHAR(2000)
) RETURNS varchar(2000) CHARSET utf8
BEGIN
DECLARE strCnt INT; -- 문자열 갯수
DECLARE i INT;
DECLARE tmpStr VARCHAR(2000);
DECLARE choStr VARCHAR(2000); -- 문자열로 만든 초성
DECLARE result VARCHAR(2000); -- 초성과 일치하는 단어
if str is null then return null; end if;
-- 문자열 갯수 : 한글 + 공백
set strCnt = ceil(length(str)/3) + ((char_length(str) - char_length(replace(str,' ','')))/2);
-- 문자열 to 초성
set i = 1;
while i <=strCnt DO
set tmpStr = substring(str, i, 1);
set choStr = concat(ifnull(choStr,''),
case when tmpStr rlike '^ㄱ' OR ( tmpStr >= '가' AND tmpStr < '까' ) then 'ㄱ'
when tmpStr rlike '^ㄲ' OR ( tmpStr >= '까' AND tmpStr < '나' ) then 'ㄲ'
when tmpStr rlike '^ㄴ' OR ( tmpStr >= '나' AND tmpStr < '다' ) then 'ㄴ'
when tmpStr rlike '^ㄷ' OR ( tmpStr >= '다' AND tmpStr < '따' ) then 'ㄷ'
when tmpStr rlike '^ㄸ' OR ( tmpStr >= '따' AND tmpStr < '라' ) then 'ㄸ'
when tmpStr rlike '^ㄹ' OR ( tmpStr >= '라' AND tmpStr < '마' ) then 'ㄹ'
when tmpStr rlike '^ㅁ' OR ( tmpStr >= '마' AND tmpStr < '바' ) then 'ㅁ'
when tmpStr rlike '^ㅂ' OR ( tmpStr >= '바' AND tmpStr < '사' ) then 'ㅂ'
when tmpStr rlike '^ㅅ' OR ( tmpStr >= '사' AND tmpStr < '싸' ) then 'ㅅ'
when tmpStr rlike '^ㅆ' OR ( tmpStr >= '싸' AND tmpStr < '아' ) then 'ㅆ'
when tmpStr rlike '^ㅇ' OR ( tmpStr >= '아' AND tmpStr < '자' ) then 'ㅇ'
when tmpStr rlike '^ㅈ' OR ( tmpStr >= '자' AND tmpStr < '짜' ) then 'ㅈ'
when tmpStr rlike '^ㅉ' OR ( tmpStr >= '짜' AND tmpStr < '차' ) then 'ㅉ'
when tmpStr rlike '^ㅊ' OR ( tmpStr >= '차' AND tmpStr < '카' ) then 'ㅊ'
when tmpStr rlike '^ㅋ' OR ( tmpStr >= '카' AND tmpStr < '타' ) then 'ㅋ'
when tmpStr rlike '^ㅌ' OR ( tmpStr >= '타' AND tmpStr < '파' ) then 'ㅌ'
when tmpStr rlike '^ㅍ' OR ( tmpStr >= '파' AND tmpStr < '하' ) then 'ㅍ'
when tmpStr rlike '^ㅎ' OR ( tmpStr >= '하' ) then 'ㅎ'
else tmpStr end);
set i=i+1;
end while;
RETURN choStr;
END;
한글에 해당하지 않는경우에는 기존 값으로 리턴하도록 수정하였습니다.
검색하려는 대상에 한글뿐만 아니라, 문자, 특수문자가 존재할 수 있기 때문입니다.
이제 쿼리에서는 아래와 같이 초성일 때와 문자일 경우 모두 검색이 되도록 작성합니다.
AND (T1.TITL LIKE CONCAT('%', #{keyword}, '%') OR FNC_NTCN(T1.TITL) LIKE CONCAT('%', #{keyword}, '%')
OR T1.CTNT LIKE CONCAT('%', #{keyword}, '%') OR FNC_NTCN(T1.CTNT) LIKE CONCAT('%', #{keyword}, '%'))
이제 프론트쪽 코드를 보도록 하죠.
기존에 초성을 추출하는 getChoHangul 이라는 함수에서 아스키코드로 문자타입을 분류하는 함수를 별도로 작성하였습니다. 다른데서도 문자의 타입을 구분 할 일이 있을 것 같아서 입니다.
distStr : function(str){
var size = str.length;
var ascii = "";
var getCharType = function(char){
ascii = char.charCodeAt(0);
if(ascii == 32){ /*공백*/
return "blank"
}else if (ascii>=48 && ascii<=57){ /*숫자*/
return "number"
}else if (ascii>=65 && ascii<=90){ /*영어 대문자*/
return "upperEng";
}else if (ascii>=97 && ascii<=122){ /*영어 소문자*/
return "lowerEng";
}else if ((ascii>=33 && ascii<=47)
|| (ascii>=58 && ascii<=64)
|| (ascii>=91 && ascii<=96)
|| (ascii>=123 && ascii<=126)){ /*특수문자*/
return "spChar";
}else if(ascii >= 44032 && ascii <= 55203){ /*한글*/
return "kor"
}else if(ascii >= 12593 && ascii <= 12622){ /*한글자음*/
return "vowKor";
}else if (ascii >= 12623 && ascii <= 12643){ /*한글모음*/
return "conKor";
}
}
var result = [];
for(var i in str){
var type = getCharType(str[i]);
if(result.indexOf(type) === -1) result.push(type);
}
return (result.length === 1) ? result[0] : result;
},
단순하게 아스키코드로 문자열에 있는 타입들을 리턴해주는 함수 입니다.
한개일 경우 String으로 복수의 타입이 있을 경우 배열로 리턴하게 됩니다.
getChoHangul : function(str) {
var cho = ["ㄱ","ㄲ","ㄴ","ㄷ","ㄸ","ㄹ","ㅁ","ㅂ","ㅃ","ㅅ","ㅆ","ㅇ","ㅈ","ㅉ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"];
var result = "", charType = "";
var size = str.length;
for(var i=0;i<size;i++) {
charType = this.distStr(str[i]);
if(charType == "kor"){
var code = str.charCodeAt(i)-44032;
if(code>-1 && code<11172){
result += cho[Math.floor(code/588)];
}
}else{
result += str[i];
}
}
return result;
},
수정된 초성검색 함수는 위의 distStr 함수를 활용하여 한글의 초성만 추출을 하고 다른 경우는 그대로 리턴하게 됩니다.
예) "현대 g80" => "ㅎㄷ g80"
아래는 추가된 getChoMatch 함수 입니다.
문자열에서 초성에 해당하는 문자를 추출해 배열로 리턴해주게 됩니다.
getChoMatch : function(keyword, data){
var keywordCho = keyword.toLowerCase();
var dataCho = this.getChoHangul(data).toLowerCase();
if(keywordCho === "") keywordCho = keyword;
var strArray = [], resultArray = [];
var opt = true;
while(opt){
if(i == 20) opt = false;
var strIdx = dataCho.indexOf(keywordCho);
if(strIdx !== -1){
strArray.push(strIdx);
dataCho = dataCho.substr(strIdx+keywordCho.length);
}else{
opt = false;
}
}
var beforeValue = 0, val = "";
for(var i in strArray){
val = data.substr(strArray[i]+beforeValue, keywordCho.length);
if(resultArray.indexOf(val) == -1) resultArray.push(val);
beforeValue += strArray[i]+keywordCho.length;
}
return resultArray;
},
예를들어 "ㄱㄴ" 과 "가나다라가누가도" 를 파라메터로 넘기게 되면 ["가나", 가누"] 가 리턴이 되게 됩니다.
이 함수는 검색 후에 초성에 해당하는 문자를 하이라이트 처리 하거나 할때 활용하였습니다.
이제 한글, 초성(자음), 영문 대소문자, 숫자 특수문자를 검색하여도 출력이 되게 됩니다.
'Programing > JavaScript' 카테고리의 다른 글
prototype chain 에 대하여, 상속의 개념, 중복을 줄이자! (0) | 2020.11.04 |
---|---|
javascript 의 상속 첫번째 prototype 기반의 상속 (0) | 2020.10.27 |
javascript 요소(Element)의 이동 추가 삽입 insertBefore() (0) | 2020.09.28 |
Javascript Object Extend, merge, copy 객체 합치기, 병합하기 복사하기 assign (0) | 2020.03.16 |
customoverlay를 활용한 kakaomap marker 회전 마커회전 (2) | 2020.02.24 |
댓글