2. 한글 초·중·종성 분리 함수: FN_APARTCHR
초성 검색을 넘어, 한글 한 글자를 초성·중성·종성 단위로 완전히 분리해야 할 때가 있습니다.
예를 들어 '각'을 'ㄱㅏㄱ'으로 분해하여 형태소 분석이나 유사도 검사에 활용하는 경우입니다.
이 로직은 한글 유니코드의 구성 원리를 기반으로 합니다.
2.1 핵심 분해 함수: FN_APARTCHR
아래 함수는 입력된 한 글자가 한글 완성형 범위(AC00 ~ D7A3)에 속하는지 확인한 후, 유니코드 공식을 적용하여 자모를 분리합니다.
CREATE OR REPLACE FUNCTION FN_APARTCHR(P_CHAR IN VARCHAR2)
RETURN VARCHAR2
IS
ExceptNoHangul EXCEPTION;
startHanUniDec NUMBER;
calHanUniDec NUMBER;
tmpUniDec NUMBER;
initUniDec NUMBER;
vowelUniDec NUMBER;
finUniDec NUMBER;
initStr VARCHAR2(10);
vowelStr VARCHAR2(10);
finStr VARCHAR2(10);
BEGIN
-- 한글 완성형 범위(AC00 ~ D7A3) 확인
IF ASCIISTR(P_CHAR) NOT BETWEEN '\AC00' AND '\D7A3' THEN
RETURN P_CHAR; -- 한글 아니면 원문 반환
END IF;
startHanUniDec := FN_HEX_TO_DEC('AC00'); -- '가' 유니코드
calHanUniDec := FN_HEX_TO_DEC(REPLACE(ASCIISTR(P_CHAR), '\', ''));
tmpUniDec := calHanUniDec - startHanUniDec;
-- 초성 계산 (588 = 21 * 28)
initUniDec := FLOOR(tmpUniDec/588) + FN_HEX_TO_DEC('1100');
initStr := UNISTR('\' || FN_DEC_TO_HEX(initUniDec));
-- 중성 계산
vowelUniDec := FLOOR(MOD(tmpUniDec, 588) / 28) + FN_HEX_TO_DEC('1161');
vowelStr := UNISTR('\' || FN_DEC_TO_HEX(vowelUniDec));
-- 종성 계산
finUniDec := MOD(MOD(tmpUniDec, 588), 28) + FN_HEX_TO_DEC('11A8') - 1;
IF MOD(MOD(tmpUniDec, 588), 28) = 0 THEN
finStr := NULL;
ELSE
finStr := UNISTR('\' || FN_DEC_TO_HEX(finUniDec));
END IF;
RETURN initStr || vowelStr || finStr;
EXCEPTION
WHEN OTHERS THEN RETURN 'ERROR:' || SQLERRM;
END;
⚠️ 주의사항:
위 코드가 정상 동작하려면 16진수 변환을 담당하는
위 코드가 정상 동작하려면 16진수 변환을 담당하는
FN_DEC_TO_HEX와 FN_HEX_TO_DEC 보조 함수가
먼저 생성되어 있어야 합니다. (이전 섹션을 참고하세요.)
2.2 문자열 전체 분해: FN_GET_DIV_KO_CHAR
마지막으로, 문자열 전체를 루프(Loop) 돌며 변환하는 래퍼 함수입니다.
CREATE OR REPLACE FUNCTION FN_GET_DIV_KO_CHAR(i_p1 IN VARCHAR2)
RETURN VARCHAR2
AS
l_rt VARCHAR2(4000);
BEGIN
FOR i IN 1 .. LENGTH(i_p1) LOOP
l_rt := l_rt || FN_APARTCHR(SUBSTR(i_p1, i, 1));
END LOOP;
RETURN l_rt;
END;
댓글
댓글 쓰기