본문 바로가기
study/TIP

CUBRID 한글 초성 검색

by 휘루걸음 2024. 3. 7.
728x90
반응형

한글 초성검색이 필요하다는 요청이 왔습니다.

db에서 한방에 해결하고 싶지만 안되는 경우가 있습니다.

이번에도 그런 경우가 발생하여, 기록으로 남깁니다.

반응형
728x90

ONLY SQL

일단 사용중인 db에서 제공되는 함수가 있다면, 직접적인 쿼리에서 해결하고 싶었지만 제공하지 않습니다.

정규식으로 한글만 걸러내려니, 정규식으로 체크는 가능하지만 replace 기능은 제공하지 않는다는 답변이었습니다.

https://www.cubrid.com/qna/3821072

https://www.cubrid.com/qna/3834616

 TRIM(TRANSLATE(NVL(UPPER(CHEM_NAME_KOR),''),'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ()+/-,&#;[].%ㆍ㎎→:', '')) AS str,

 

 

일단 한글을 제외한 나머지를 날려버리기 위해, replace 처리를 합니다.

한글만 남도록 정제 후, 검색어(초성) 한글자 한글자 잘라서, 문자열의 각 글자와 비교합니다.

일부만 입력해도 전체 문장과 비교해서 처리하자니 너무 오래 걸리고, 쿼리문도 복잡해집니다. 

첫글자부터 INDEX에 맞게 비교하고, 각 초성을 비교하자니 제약도 있고, 이 역시 복잡해서 싫습니다.

이건 아닌것 같다는 생각이 강하게 듭니다.

외부에서 가공합니다

한글결과 값을 JAVA로 가져와서 초성으로 변환하는 작업을 진행합니다.

입력: 비스메시틸아미노 안트라퀴논
초성: ᄇᄉᄆᄉᄐᄋᄆᄂ ᄋᄐᄅᄏᄂ

입력: 벤조산 김치
초성: ᄇᄌᄉ ᄀᄎ

---------------


public class testRegex {
	
	 public static void main(String[] args) {
		 String input1 = "비스메시틸아미노 안트라퀴논";
	        String input2 = "벤조산 김치";

	        System.out.println("입력: " + input1);
	        System.out.println("초성: " + getKoreanInitials(input1));	        
	 

	        System.out.println("\n입력: " + input2);
	        System.out.println("초성: " + getKoreanInitials(input2));
	        
	    }

	   

	 private static String getKoreanInitials(String input) {
	        StringBuilder result = new StringBuilder();

	        for (char ch : input.toCharArray()) {
	            if (Character.isWhitespace(ch)) {
	                // 공백은 그대로 추가
	                result.append(ch);
	            } else if (isHangul(ch)) {
	                // 초성 = ((한글 유니코드 - 44032) / 28) / 21 + 4352
	                int initialIndex = ((ch - 44032) / 28) / 21 + 4352;
	                result.append((char) initialIndex);
	            } else {
	                // 한글이 아닌 경우 그대로 추가
	                result.append(ch);
	            }
	        }

	        return result.toString();
	    }


	    private static boolean isHangul(char ch) {
	        return 0xAC00 <= ch && ch <= 0xD7A3;
	    }
	    

}

 

ᄇᄌᄉ ᄀᄎ

결과가 조금 이상합니다. 분명 초성이 맞는데, 좀 생긴게 위로 붙었어요.

그래도 생긴게 맞으니, 맞겠지? 하지만 정상적으로 검색이 되지 않습니다.

 

유니코드에서 한글 초성(ᄇᄌᄉ)과 키보드에서 입력하는 한글 초성(ㅂㅈㅅ)은 서로 다른 값입니다. 유니코드에서 한글 음절은 '가'부터 시작하여 초성, 중성, 종성의 조합으로 구성됩니다. 유니코드의 한글 초성은 키보드에서 입력하는 초성과 직접적으로 일치하지 않습니다.

키보드에서 입력하는 한글 초성은 키보드 자판 배열에 따라서 결정되며, 키보드의 배열은 다양한 규칙에 따라 구성되어 있습니다. 일반적으로 "ㅂ", "ㅈ", "ㅅ" 등의 키를 누르면 키보드 드라이버가 해당하는 초성을 입력으로 받아서 응용 프로그램에 전달합니다. 이는 키보드의 레이아웃과 관련이 있습니다.

한편, 유니코드에서의 한글 초성은 한글 음절의 기본 구성 요소 중 하나이며, 'ㄱ', 'ㄴ', 'ㄷ' 등으로 표현됩니다. 초성이 키보드의 배열과 일치하지 않는 이유는 키보드의 역사적인 배치와 유니코드에서의 문자 인코딩 체계가 다르기 때문입니다.

 

다른 방향으로 개선할 방법을 찾아봅니다.

 

public class testRegex3 {

    public static void main(String[] args) {
        String input1 = "비스메시틸아미노 안트라퀴논";
        String input2 = "벤조산 김치";
        
        System.out.println("입력: " + input1);
        getInitialString(input1);        

        System.out.println("\n입력: " + input2);
        getInitialString(input2);
                
    }
    static String [] INITIAL_STRING = {
            "ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", 
            "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", 
            "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", 
            "ㅋ", "ㅌ", "ㅍ", "ㅎ" };
    	

    public static void getInitialString(String stringContent) {
        String initialString = "";

        if (stringContent != null && !stringContent.isEmpty()) {
            for (int i = 0; i < stringContent.length(); i++) {
                String stringLocationInfo = String.valueOf(stringContent.charAt(i));
                if (stringLocationInfo.matches(".*[가-힣]+.*")) {
                    if (stringLocationInfo.charAt(0) >= 0xAC00) {
                        int unicode = stringLocationInfo.charAt(0) - 0xAC00;
                        int index = ((unicode - (unicode % 28)) / 28) / 21;
                        initialString += INITIAL_STRING[index];
                    }
                } else {
                    initialString += stringLocationInfo;
                }
            }
            System.out.println("초성: " + initialString);
        }
    }
}

 

문자열의 유니코드를 인덱스로 반환하도록 우회 처리한 소스입니다.

초성 유니코드를 그대로 사용할 경우, 검색창에 키보드로 입력한 초성과는 다른 값이기 때문에, 찾아낸 초성을 다시 매핑해주는 과정을 거칩니다.

 

 

이후에는 각 자 입맛에 맞게 요리하시면 되겠습니다. 

java stored procedure 를 활용하거나, DB에 넣고 활용하면 되겠습니다.


참고

- 연락처에 있는 초성, 중성, 종성을 분류하고 비교하는 과정 중
- 자음으로만 저장된 연락처정상적인 연락처를 비교 
ex) 'ㄱㄱㄴ' , '가나다'

- 두 문자열의 첫번째 초성값들을 비교
- 뽑아낸 초성 자음 'ㄱ' 와 'ㄱ' 를 isEqualString을 통해 비교
- false가 리턴 !!

 

Why??

내가 보기엔  'ㄱ' 'ㄱ'의 비교                         ----->  같은 자음 'ㄱ' 과 'ㄱ'  같은 것 처럼 보임.

컴퓨터가 보기엔 '12593''4352'의 비교      ----->  단일 자음 'ㄱ'과 초성 자음 'ㄱ' 차이가 존재.

 

 

   

 


아래 표와 같이 초성 자음과 종성 및 단일 자음의 유니코드 값이 다릅니다.

( 실제로는 자음마다 총 5개의 유니코드 값이 존재합니다. )

초성 자음                  

종성 및 단일 자음            종성 및 단일 자음 중 19개

4352 12593 ㄱ                    12593 ㄱ  

4353 12594 ㄲ                    12594

4354 12595 ㄳ                    12596

4355 12596 ㄴ                    12599

4356 12597 ㄵ                    12600

4357 12598 ㄶ                    12601

4358 12599 ㄷ                    12609

4359 12600 ㄸ                    12610

4360 12601 ㄹ                    12611

4361 12602 ㄺ                    12613

4362 12603 ㄻ                    12614

4363 12604 ㄼ                    12615

4364 12605 ㄽ                    12616

4365 12606 ㄾ                    12617

4366 12607 ㄿ                    12618

4367 12608 ㅀ                    12619

4368 12609 ㅁ                    12620

4369 12610 ㅂ                    12621

4370 12611 ㅃ                    12622

  12612  

  12613  

  12614  

  12615   

  12616  

          12617  

  12618  

  12619  

  12620  

  12621  

  12622  

 

(IOS) 자음의 유니코드 값 확인 코드 

 

 // unichar 로 변수 선언
 // 자음이 들어있는 strConsonant 변수안에 0번재 값을 집어넣습니다.
 unichar oneChar = [strConsonant characterAtIndex:0];
 // NSLog를 통해 %d값으로 int값 출력해서 유니코드 값을 확인할 수 있습니다.
 NSLog("UNICODE : %d", oneChar);

출처: https://winplz.tistory.com/entry/한글-자음-비교같지만-다른-자음들 [윈플:티스토리]

728x90
반응형

'study > TIP' 카테고리의 다른 글

Chocolatey 셋팅오류 해결방법  (0) 2024.04.23
rath 셋팅  (1) 2024.03.28
java array copy  (0) 2024.03.03
html to image  (0) 2024.03.03
한글주소 인코딩, url encode  (1) 2024.02.27