[Java] 자바로 한글 자모(초성,중성,종성) 분리(추출)하기 (+개념)

    현재 유니코드로 대부분의 문자열을 추출하기 때문에 본 포스팅도 유니코드를 기반의 한글 자모 추출 내용이다. 우리가 한글에서 자모를 추출하기 위해서는 유니코드에서 한글이 어느위치에 있는지를 알아야 한다. (참고로 파이썬에 관련된 자모 추출이 궁금하면 포스팅 맨 하단의 링크글로 들어가면 된다.)

     

    한글 자모 추출하기

     

    유니코드는 마구잡이로 한글을 넣지 않았고 초성, 중성, 종성의 조합으로 값을 넣게 되었는데 반대로 이 조합을 알면 현재의 한글을 초성, 중성, 중성으로 분리할 수 있다는 말이 된다. 비슷한 개념으로 영어의 소문자(97~122)와 대문자(65~90)의 변환을 32로 빼고 더하는 것으로 변환할 수 있는 것과 유사하다. 유니코드에서 한글의 시작점은 AC00값이며, 이 값은 한글로 "가"이다. 즉 이 값을 기준으로 유니코드의 위치값을 계산하면 초중종성 즉 자모를 추출할 수 있게 된다.

     

    초중종성 순서

    우선 값을 계산하기에 앞서 초성, 중성, 종성의 순서를 알아야 한다. 아래는 초/중/종성을 배열 형태로 만든 것이다.

    초성 위치값

    String[] CHO = {"ㄱ","ㄲ","ㄴ","ㄷ","ㄸ","ㄹ","ㅁ","ㅂ","ㅃ",
    			"ㅅ","ㅆ","ㅇ","ㅈ","ㅉ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"};

    중성 위치값

    String[] JOONG = {"ㅏ","ㅐ","ㅑ","ㅒ","ㅓ","ㅔ","ㅕ","ㅖ","ㅗ","ㅘ",
    			"ㅙ","ㅚ","ㅛ","ㅜ","ㅝ","ㅞ","ㅟ","ㅠ","ㅡ","ㅢ","ㅣ"};	

    종성 위치값

    String[] JONG = {"","ㄱ","ㄲ","ㄳ","ㄴ","ㄵ","ㄶ","ㄷ","ㄹ","ㄺ","ㄻ","ㄼ",
    			"ㄽ","ㄾ","ㄿ","ㅀ","ㅁ","ㅂ","ㅄ","ㅅ","ㅆ","ㅇ","ㅈ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"};

    참고로 종성의 시작은 "없다"로 시작이 되기에 위와 같이 공백 값을 배열에 넣었다

     

     

    한글이 유니코드에 저장되는 규칙

    한글은 다음과 같은 규칙으로 유니코드값이 생성된다.

    (초성 * 21 + 중성) * 28 + 종성 + 0xAC00

    위의 배열값을 기반으로 "안"이라는 말을 뽑자면, 초성의 "ㅇ"는 11번째, "ㅏ"는 0번째, "ㄴ"는 4번째위치에 존재한다. 이 값을 그대로 자바에서 코딩을 하면

     

    안이 나온 결과

     

    위와 같이 정상적으로 "안"이라는 글자가 출력된 것을 확인할 수 있다. 한글을 만드는 법을 알았으니 이제 자모를 추출하는 방법을 구해보도록 한다.

     

    초성 공식

    초성 =  ((문자유니코드 - 0xAC00)/28)/21

    현재의 한글 유니코드 값에 - 0xAC00 즉 한글 시작점을 뺀 후, 중성 개수와 종성 개수를 나눈다. 안의 유니코드 값과 함게 안에서 "ㅇ"을 추출하는 것을 해본다면

     

    char uniVal = "안".charAt(0);
    char cho = (char)((uniVal-0xAC00)/28/21);
    System.out.println(uniVal + "[" + (int)cho + "]");
    
    // 결과 안[11]

    위와 같이 실행을 하게 되면 "안[11]"이라는 값이 나오고, 즉 초성으로 11번째 인덱스라는 값을 추출한 것을 확인할 수 있다.

     

    중성 공식

    중성 = (문자유니코드 - 0xAC00) / 28 % 21

    현재의 한글 코드 값에 한글 시작점을 뺀 후, 종성 개수로 나눈 후, 중성의 나머지 값을 출력한다.

     

    char uniVal = "안".charAt(0);
    char joong = (char)((uniVal-0xAC00)/28%21);
    System.out.println(uniVal + "[" + (int)joong + "]");
    
    // 안[0]

    위 코드를 실행하면 안[0] 이라는 값이 출력되는데 "ㅏ"는 0번째 값이기 때문에 정상적으로 나온 것을 확인할 수 있다.

     

    종성 공식

    종성 = (문자유니코드 - 0xAC00) % 28

    종성 공식은 매우 간단하다. 차이값에 28의 나머지를 구하면 된다.

     

    char uniVal = "안".charAt(0);
    char jong = (char)((uniVal-0xAC00)%28);
    System.out.println(uniVal + "[" + (int)jong + "]");
    
    // 안[4]

    위 코드를 실행하면 "ㄴ"의 종성 위치인 4번째 값이 출력되는 것을 확인할 수 있다. 이제 이 인덱스 값을 기반으로 초성/중성/종성을 호출하면 자모를 추출 할 수 있게 된다.

     

     

    자모 추출 최종 소스

    public class Main {
    	final static String[] CHO = {"ㄱ","ㄲ","ㄴ","ㄷ","ㄸ","ㄹ","ㅁ","ㅂ","ㅃ",
    			"ㅅ","ㅆ","ㅇ","ㅈ","ㅉ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"};
    	
    	final static String[] JOONG = {"ㅏ","ㅐ","ㅑ","ㅒ","ㅓ","ㅔ","ㅕ","ㅖ","ㅗ","ㅘ",
    			"ㅙ","ㅚ","ㅛ","ㅜ","ㅝ","ㅞ","ㅟ","ㅠ","ㅡ","ㅢ","ㅣ"};			
    	
    	final static String[] JONG = {"","ㄱ","ㄲ","ㄳ","ㄴ","ㄵ","ㄶ","ㄷ","ㄹ","ㄺ","ㄻ","ㄼ",
    			"ㄽ","ㄾ","ㄿ","ㅀ","ㅁ","ㅂ","ㅄ","ㅅ","ㅆ","ㅇ","ㅈ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"};
    
    	public static void main(String[] args) {
    		String text = "안녕하세요. 닭가슴살은 퍽퍽하고, 스타벅스 자바칩프라푸치노 맛나요ㅋㅋ";
    		
    		for(int i = 0; i < text.length(); i++) {
    			char uniVal = text.charAt(i);
    			
    			// 한글일 경우만 시작해야 하기 때문에 0xAC00부터 아래의 로직을 실행한다
    			if(uniVal >= 0xAC00) {
    				System.out.print(uniVal + "=>");
    				uniVal = (char)(uniVal - 0xAC00);
    				
    				char cho = (char)(uniVal/28/21);
    				char joong = (char) ((uniVal)/28%21);
    				char jong = (char) (uniVal % 28);	// 종성의 첫번째는 채움이기 때문에
    						
    				System.out.println(CHO[cho] + JOONG[joong] + JONG[jong]);
    			} else {
    				System.out.println(uniVal + "=>" + uniVal);
    			}
    		}
    	}
    }

     

    자모 추출 공식을 보면 현재유니코드 - 0xAC00은 Default이기 때문에 시작부터 0xAC00을 뺀 값을 변수로 가면 소스가 좀 더 심플해진다. 자모가 결합된 문자가 아닌 경우 else로 처리한다. "ㅋㅋㅋ"와 같이 자음만 있는 한글의 경우 0xAC00보다 낮은 유니코드값을 갖기 때문에 그대로 else로 출력한다.

     

    실행결과

    안=>ㅇㅏㄴ
    녕=>ㄴㅕㅇ
    하=>ㅎㅏ
    세=>ㅅㅔ
    요=>ㅇㅛ
    .=>.
     => 
    닭=>ㄷㅏㄺ
    가=>ㄱㅏ
    슴=>ㅅㅡㅁ
    살=>ㅅㅏㄹ
    은=>ㅇㅡㄴ
     => 
    퍽=>ㅍㅓㄱ
    퍽=>ㅍㅓㄱ
    하=>ㅎㅏ
    고=>ㄱㅗ
    ,=>,
     => 
    스=>ㅅㅡ
    타=>ㅌㅏ
    벅=>ㅂㅓㄱ
    스=>ㅅㅡ
     => 
    자=>ㅈㅏ
    바=>ㅂㅏ
    칩=>ㅊㅣㅂ
    프=>ㅍㅡ
    라=>ㄹㅏ
    푸=>ㅍㅜ
    치=>ㅊㅣ
    노=>ㄴㅗ
     => 
    맛=>ㅁㅏㅅ
    나=>ㄴㅏ
    요=>ㅇㅛ
    ㅋ=>ㅋ
    ㅋ=>ㅋ
    

     

    연관포스팅

    [Java] 자바 아스키코드및 유니코드로 문자 변환

    [Python] 파이썬을 이용한 자모(초성/중성/종성) 분리 및 결합하기

    댓글

    Designed by JB FACTORY