원본 본문으로 이동하기

한글 분해 (자바 예제 포함)

박용서 - 아주 오래전에 만들어둔 한글 분해인데... 최근 필요할 일이 있을 수 있어 올립니다. 유니코드의 한글은 아래와 같이 할당되어있습니다. 자음 ㄱ : 12593 / ㄲ : 12594 / ㄳ : 12595 / ㄴ : 12596 ... ㅎ : 12622 모음 ㅏ : 12623 / ㅐ : 12624 / ㅑ : 12625 / ㅒ : 12626 ... ㅣ : 12643 완성자 가 : 44032 / 각 : 44033/ 갂 : 44034/ 갃 : 44035 ... 힣 : 55203 초성순서 총 19자 ㄱ ㄲ ㄴ ㄷ ㄸ ㄹ ㅁ ㅂ ㅃ ㅅ ㅆ ㅇ ㅈ ㅉ ㅊ ㅋ ㅌ ㅍ ㅎ 중성순서 총 21자 ㅏ ㅐ ㅑ ㅒ ㅓ ㅔ ㅕ ㅖ ㅗ ㅘ ㅙ ㅚ ㅛ ㅜ ㅝ ㅞ ㅟ ㅠ ㅡ ㅢ ㅣ 종성순서 총 28자 (받침없음 포함) (받침없음) ㄱ ㄲ ㄳ ㄴ ㄵ ㄶ ㄷ ㄹ ㄺ ㄻ ㄼ ㄽ ㄾ ㄿ ㅀ ㅁ ㅂ ㅄ ㅅ ㅆ ㅇ ㅈ ㅊ ㅋ ㅌ ㅍ ㅎ 위 초성/중성/종성을 반복하여 표시됩니다. 중성 21자 종성 28자를 곱하면 588(=21 * 28)자 가 됩니다. 즉 가의 코드가 '가' : 44032 라면 다음 초성 ㄲ의 첫 글자인 '까'의 코드는 44620(=44032 + 588(=21 * 28))이 됩니다. 이것을 응용하면 중성까지 나눠진 상태에서 종성이 0(28로 나누어 떨어지는 경우)일 경우 종성(받침)이 없는 글자가 됩니다. 설명이.. 이상한 것 같으니.. 아래 코드예제를 적어두었습니다. 예제 너무 오래전에 짠거라.. 네이밍이과.. 소스가 개판.. ㅠㅠ...입니다..; 요즘 스타일로 짜면 배열이 아니라 static에 switch 함수를 두고 자바8의 스트림으로 빼는 것도 좋다고 생각합니다. // 일반 분해 private final static char[] KO_INIT_S = { 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' }; // 19 private final static char[] KO_INIT_M = { 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ' }; // 21 private final static char[] KO_INIT_E = { 0, 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' }; // 28 // 완전 분해 private final static char[][] KO_ATOM_S = { { 'ㄱ' }, { 'ㄱ', 'ㄱ' }, { 'ㄴ' }, { 'ㄷ' }, { 'ㄷ', 'ㄷ' }, { 'ㄹ' }, { 'ㅁ' }, { 'ㅂ' }, { 'ㅂ', 'ㅂ' }, { 'ㅅ' }, { 'ㅅ', 'ㅅ' }, { 'ㅇ' }, { 'ㅈ' }, { 'ㅈ', 'ㅈ' }, { 'ㅊ' }, { 'ㅋ' }, { 'ㅌ' }, { 'ㅍ' }, { 'ㅎ' } }; private final static char[][] KO_ATOM_M = { { 'ㅏ' }, { 'ㅐ' }, { 'ㅑ' }, { 'ㅒ' }, { 'ㅓ' }, { 'ㅔ' }, { 'ㅕ' }, { 'ㅖ' }, { 'ㅗ' }, { 'ㅗ', 'ㅏ' }, { 'ㅗ', 'ㅐ' }, { 'ㅗ', 'ㅣ' }, { 'ㅛ' }, { 'ㅜ' }, { 'ㅜ', 'ㅓ' }, { 'ㅜ', 'ㅔ' }, { 'ㅜ', 'ㅣ' }, { 'ㅠ' }, { 'ㅡ' }, { 'ㅡ', 'ㅣ' }, { 'ㅣ' } }; private final static char[][] KO_ATOM_E = { {}, { 'ㄱ' }, { 'ㄱ', 'ㄱ' }, { 'ㄱ', 'ㅅ' }, { 'ㄴ' }, { 'ㄴ', 'ㅈ' }, { 'ㄴ', 'ㅎ' }, { 'ㄷ' }, { 'ㄹ' }, { 'ㄹ', 'ㄱ' }, { 'ㄹ', 'ㅁ' }, { 'ㄹ', 'ㅂ' }, { 'ㄹ', 'ㅅ' }, { 'ㄹ', 'ㅌ' }, { 'ㄹ', 'ㅍ' }, { 'ㄹ', 'ㅎ' }, { 'ㅁ' }, { 'ㅂ' }, { 'ㅂ', 'ㅅ' }, { 'ㅅ' }, { 'ㅅ', 'ㅅ' }, { 'ㅇ' }, { 'ㅈ' }, { 'ㅊ' }, { 'ㅋ' }, { 'ㅌ' }, { 'ㅍ' }, { 'ㅎ' } }; // 쌍자음이나 이중모음을 분해 private final static char[][] KO_ATOM_P = { { 'ㄱ' }, { 'ㄱ', 'ㄱ' }, { 'ㄱ', 'ㅅ' }, { 'ㄴ' }, { 'ㄴ', 'ㅈ' }, { 'ㄴ', 'ㅎ' }, { 'ㄷ' }, { 'ㄸ' }, { 'ㄹ' }, { 'ㄹ', 'ㄱ' }, { 'ㄹ', 'ㅁ' }, { 'ㄹ', 'ㅂ' }, { 'ㄹ', 'ㅅ' }, { 'ㄹ', 'ㄷ' }, { 'ㄹ', 'ㅍ' }, { 'ㄹ', 'ㅎ' }, { 'ㅁ' }, { 'ㅂ' }, { 'ㅂ', 'ㅂ' }, { 'ㅂ', 'ㅅ' }, { 'ㅅ' }, { 'ㅅ', 'ㅅ' }, { 'ㅇ' }, { 'ㅈ' }, { 'ㅈ', 'ㅈ' }, { 'ㅊ' }, { 'ㅋ' }, { 'ㅌ' }, { 'ㅍ' }, { 'ㅎ' }, { 'ㅏ' }, { 'ㅐ' }, { 'ㅑ' }, { 'ㅒ' }, { 'ㅓ' }, { 'ㅔ' }, { 'ㅕ' }, { 'ㅖ' }, { 'ㅗ' }, { 'ㅗ', 'ㅏ' }, { 'ㅗ', 'ㅐ' }, { 'ㅗ', 'ㅣ' }, { 'ㅛ' }, { 'ㅜ' }, { 'ㅜ', 'ㅓ' }, { 'ㅜ', 'ㅔ' }, { 'ㅜ', 'ㅣ' }, { 'ㅠ' }, { 'ㅡ' }, { 'ㅡ', 'ㅣ' }, { 'ㅣ' } }; /** 한글부분을 초성으로 교체합니다. */ public static String toKoChosung(String text) { if (text == null) { return null; } // 한글자가 한글자와 그대로 대응됨. // 때문에 기존 텍스트를 토대로 작성된다. char[] rv = text.toCharArray(); char ch; for (int i = 0 ; i < rv.length ; i++) { ch = rv[i]; if (ch >= '가' && ch <= '힣') { rv[i] = KO_INIT_S[(ch - '가') / 588]; // 21 * 28 } } return new String(rv); } /** 한글부분을 자소로 분리합니다. <br>많다 = [ㅁㅏㄶㄷㅏ] */ public static String toKoJaso(String text) { if (text == null) { return null; } // StringBuilder의 capacity가 0으로 등록되는 것 방지. if (text.length() == 0) { return ""; } // 한글자당 최대 3글자가 될 수 있다. // 추가 할당 없이 사용하기위해 capacity 를 최대 글자 수 만큼 지정하였다. StringBuilder rv = new StringBuilder(text.length() * 3); for (char ch : text.toCharArray()) { if (ch >= '가' && ch <= '힣') { // 한글의 시작부분을 구함 int ce = ch - '가'; // 초성을 구함 rv.append(KO_INIT_S[ce / (588)]); // 21 * 28 // 중성을 구함 rv.append(KO_INIT_M[(ce = ce % (588)) / 28]); // 21 * 28 // 종성을 구함 if ((ce = ce % 28) != 0) { rv.append(KO_INIT_E[ce]); } } else { rv.append(ch); } } return rv.toString(); } /** 한글부분을 자소로 완전 분리합니다. <br>많다 = [ㅁㅏㄴㅎㄷㅏ]*/ public static String toKoJasoAtom(String text) { if (text == null) { return null; } // StringBuilder의 capacity가 0으로 등록되는 것 방지. if (text.length() == 0) { return ""; } // 한글자당 최대 6글자가 될 수 있다. // 추가 할당 없이 사용하기위해 capacity 를 최대 글자 수 만큼 지정하였다. StringBuilder rv = new StringBuilder(text.length() * 6); for (char ch : text.toCharArray()) { if (ch >= '가' && ch <= '힣') { // 한글의 시작부분을 구함 int ce = ch - '가'; // 초성을 구함 rv.append(KO_ATOM_S[ce / (588)]); // 21 * 28 // 중성을 구함 rv.append(KO_ATOM_M[(ce = ce % (588)) / 28]); // 21 * 28 // 종성을 구함 if ((ce = ce % 28) != 0) { rv.append(KO_ATOM_E[ce]); } } // 쌍자음과 이중모음 분리 else if (ch >= 'ㄱ' && ch <= 'ㅣ') { rv.append(KO_ATOM_P[ch - 'ㄱ']); } else { rv.append(ch); } } return rv.toString(); } - 문자셋 자바