이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.
아주 오래전에 만들어둔 한글 분해인데… 최근 필요할 일이 있을 수 있어 올립니다.
유니코드의 한글은 아래와 같이 할당되어있습니다. 자음 ㄱ : 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();
}