[ Java ] 한글 검색하게 해주는 정규식 만들기

2023. 10. 5. 08:51언어/JAVA

728x90
반응형

화면에서 한글을 검색할 경우 마지막 글자에 초성이 생기는 경우가 있습니다.

예) "인텔리제이" 검색 시 "인ㅌ", 인텔ㄹ"

 

이럴 때 초성값을 가져와 정규식을 만들어서 넘기는 로직을 만들어 보겠습니다.

 

public class HangeulRegex {

    // 마지막 글자
    private String initialWord;
    
    // 마지막 글자의 유니코드 값
    private int unicodePoint;
    
    // 초성 또는 초성+중성일 경우 생성될 정규식
    private String regex;
    
    // 마지막 글자에 받침이 있는지 확인
    public boolean isInFinalConsonant(String str) {
    	// 한글자일 경우에는 통과
        if(str.length() > 1) {
            initialWord = str.substring(str.length() - 1);
            unicodePoint = initialWord.codePointAt(0);
            int idx = IntStream.range(0, initialList.length)
                               .filter(i->initialWord.charAt(0) == initialList[i]).findFisrt().orElse(-1);
            
            // 초성만 있을 경우, 초성+중성만 있을 경우
            if(idx >= 0 || (unicodePoint - 0xAC00) % 28 == 0) {
            	return false;
            }
        }
    	return true;
    }
    
    // 초성 또는 초성+중성일 경우 정규식 생성
    public String getRegex(String str) {
    	regex = "";
        initialWord = str.substring(str.length() - 1);
        unicodePoint = initialWord.codePointAt(0);
        int idx = IntStream.range(0, initialList.length)
                           .filter(i->initialWord.charAt(0) == initialList[i]).findFisrt().orElse(-1);
        // 초성만 있을 경우
        if(idx >= 0) {
            regex = "["+Character.toString((char)(0xAC00 + idx*588))+"-"+Character.toString((char)(0xAC00 + idx*588 + 587)) + "]";
        }
        // 초성+중성일 경우
        if(unicodePoint - 0xAC00 >= 0 && (unicodePoint - 0xAC00) % 28 == 0) {
            regex = "["+Character.toString((char)unicodePoint)+"-"+Character.toString((char)(unicodePoint+27))+"]";
        }
        return regex;
    }
    
    // 초성이 될 수 있는 자음 목록
    private char[] initialList = {
    	'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ',
        'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ',
        'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ',
        'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
    };
}

정규식을 만들지 안만들지 판단을 해야하는데 저는 받침이 없는 글자일 경우 정규식을 생성하도록 했습니다.

그래서 initialList에 포함된 글자거나, 초성+중성으로만 이루어진 글자일 경우 false를 리턴하도록 했습니다.

 

먼저 initialList에 포함된 글자가 있을 경우 idx에 몇번째 인지 저장합니다. ㄳ, ㄶ 같은 자음은 초성이 될 수 없으므로 따로 이렇게 정의가 필요합니다. idx가 0보다 크거나 같을 경우 초성만으로 이루어진 글자입니다.

int idx = IntStream.range(0, initialList.length)
                               .filter(i->initialWord.charAt(0) == initialList[i]).findFisrt().orElse(-1);

글자의 유니코드값에서 0xAC00(가)를 뺀 다음 28로 나눈 나머지 값이 0이면 받침이 없는 글자입니다.

(unicodePoint - 0xAC00) % 28 == 0

 

그리하여 초성 또는 초성+중성으로 이루어진 글자에 대해 정규식을 생성합니다.

 

초성으로만 이루어진 글자는 이런식으로 생성합니다.

예) ㄱ → [가-깋], ㅇ → [아-잏]

 

초성+중성으로 이루어진 글자는 이런식으로 생성합니다.

예)가 → [가-갛], 요 → [요-욯]

 

이렇게 만들어진 정규식으로 MS SQL 에서는 정규식에 걸리는 내용만 검색할 수 있습니다.

SELECT *
FROM TB_TABLE
WHERE PATINDEX('%'+#{searchWord}+#{regex}+'%', COLUMN) > 0

"인텔리제이"를 검색한다고 할 때 "인텔ㄹ"을 입력했다면 searchWord에는 "인텔", regex에는 "[라-맇]"이 들어가면 됩니다.

728x90
반응형