Programing/JavaScript

vanila javascript 개선된 초성검색 기능 구현

리커니 2020. 10. 26.
반응형

vanila javascript 개선된 초성검색 기능 구현

 

이전에 포스팅한 초성검색은, 단순 한글 초성 검색을 했을 경우 값을 조회하는 기능였습니다.

 

Link : aljjabaegi.tistory.com/219

 

Oracle 오라클 자음 초성 추출 함수, 자음으로 검색, 초성 검색

Oracle 오라클 자음 초성 추출 함수, 자음으로 검색, 초성 검색 개발을 하다보면 자음으로만 검색할 수 있게 해달라는 요청이 들어오곤 한다. 그럴때마다 유용하게 사용하는 것이 아래의 함수이다

aljjabaegi.tistory.com

Link : aljjabaegi.tistory.com/220

 

Mysql 자음 초성 추출 함수, 자음으로 검색, 초성 검색

Mysql 자음 초성 추출 함수, 자음으로 검색, 초성 검색 개발을 하다보면 자음으로만 검색할 수 있게 해달라는 요청이 들어오곤 한다. 그럴때마다 유용하게 사용하는 것이 아래의 함수이다. 그냥

aljjabaegi.tistory.com

 

여기에 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;
},

 

예를들어 "ㄱㄴ" 과 "가나다라가누가도" 를 파라메터로 넘기게 되면 ["가나", 가누"] 가 리턴이 되게 됩니다. 

이 함수는 검색 후에 초성에 해당하는 문자를 하이라이트 처리 하거나 할때 활용하였습니다. 

 

이제 한글, 초성(자음), 영문 대소문자, 숫자 특수문자를 검색하여도 출력이 되게 됩니다. 

반응형

댓글

💲 추천 글