[Unicode 기준] 한글 초성/중성/종성 분리하기 & 조합하기

  • 작성일 :

Unicode (이하 ‘유니코드’) 에서의 한글은 다음과 같이 구성된다.

  1. 초성 19개 (ㄱ, ㄲ, ㄴ, ㄷ, ㄸ, ㄹ, ㅁ, ㅂ, ㅃ, ㅅ, ㅆ, ㅇ, ㅈ, ㅉ, ㅊ, ㅋ, ㅌ, ㅍ, ㅎ)
  2. 중성 21개 (ㅏ, ㅐ, ㅑ, ㅒ, ㅓ, ㅔ, ㅕ, ㅖ, ㅗ, ㅘ, ㅙ, ㅚ, ㅛ, ㅜ, ㅝ, ㅞ, ㅟ, ㅠ, ㅡ, ㅢ, ㅣ)
  3. 종성 28개 (없음, ㄱ, ㄲ, ㄳ, ㄴ, ㄵ, ㄶ, ㄷ, ㄹ, ㄺ, ㄻ, ㄼ, ㄽ, ㄾ, ㄿ, ㅀ, ㅁ, ㅂ, ㅄ, ㅅ, ㅆ, ㅇ, ㅈ, ㅊ, ㅋ, ㅌ, ㅍ, ㅎ)

 

첫번째 한글 문자는 ‘가(유니코드 44032)’ 로 시작이 되며 마지막 한글 문자 ‘힣(유니코드 55203)’ 이 된다. (총 범위 44032 ~ 55203 / 이를 벗어나면 한글이 아니다)

‘뛝’이나 ‘힣’, ‘썑’과 같이 실생활에선 사용되지 않는 문자들도 있지만 이 자체가 조합형 한글의 장점이다.

 

44032 값은 ‘가’ 가 되고 44033 값은 ‘각’ 이 된다. (44034 = 갂, 44035 = 갃, …)

44032 + 28 이 되면 초성은 그대로 유지된 상태에서 중성만 다음으로 넘어간다.

(ㅏ -> ㅐ -> ㅑ -> ㅒ … 순서)

따라서 ‘가’ 다음인 ‘까’ 를 출력하려면 ‘가’ 의 유니코드 값인 44032 588 을 더해야 한다. (44620)

다시 말하지만 이 588 이란 값은 ‘가’ 에 속한 중성과 종성을 모두 계산한 값이다. (중성 21개 * 종성 28개 = 총 588개)

만약 ‘나’ 를 출력하고자 한다면 440321176 을 더한 값(45208)이면 된다. (588 * 2 = 1176)

 

예제 페이지 : http://zective.com/crap/test.php

/**
 * 문자열을 초성/중성/종성으로 나누어 구조를 반환한다.
 *
 * @param	string	$str
 * @return	array
 */
function handec($str) {
	$result		= [];
	$hu_start	= 44032;
	$hu_last	= 55203;
	$cho_arr	= ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];
	$jung_arr	= ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'];
	$jong_arr	= ['', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];
	$cho_size	= count($cho_arr);
	$jung_size	= count($jung_arr);
	$jong_size	= count($jong_arr);
	$str		= iconv('UTF8', 'UTF-16LE', $str);
	$total_code	= [];
	$byte		= 2;
	for($leng=strlen($str), $i=0; $i<$leng; $i+=$byte) {
		if($str[$i] == ' ') {
			array_push($total_code, 20);
			array_push($result, [
				'str'	=> ' ',
				'code'	=> 20
			]);
			continue;
		}
		$byte1 = '0'.dechex(ord($str[$i + 1]));
		$byte2 = '0'.dechex(ord($str[$i]));
		$code = hexdec(
					substr($byte1, (strlen($byte1) == 3 ? 1 : 0)).
					substr($byte2, (strlen($byte2) == 3 ? 1 : 0))
				);
		array_push($total_code, $code);
		$idx = $code - $hu_start;
		$jong = $idx % $jong_size;
		$jung = (($idx - $jong) / $jong_size) % $jung_size;
		$cho = floor((($idx - $jong) / $jong_size) / $jung_size);
		$ele = [
			'str'	=> dechan($code),
			'code'	=> $code,
			'ele'	=> [
				'cho'	=> [
					'idx' => $cho,
					'str' => $cho_arr[$cho]
				],
				'jung'	=> [
					'idx' => $jung,
					'str' => $jung_arr[$jung]
				],
				'jong'	=> [
					'idx' => $jong,
					'str' => $jong_arr[$jong]
				]
			]
		];
		if($jong == 0) unset($ele['ele']['jong']);
		array_push($result, $ele);
	}
	return array_merge(['total' => $total_code], $result);
}



/**
 * 10진수 숫자를 한글로 변경한 후 반환한다.
 *
 * @param	array,int	$no
 * @return	string
 */
function dechan($no) {
	if(is_array($no)) {
		$result = '';
		foreach($no as $ele) $result .= dechan($ele);
		return $result;
	} else {
		if($no == 20) {
			return ' ';
		} else {
			$byte = 2;
			$dec = dechex($no);
			$chr = chr(hexdec(substr($dec, $byte, $byte))).chr(hexdec(substr($dec, 0, $byte)));
			return iconv('UTF-16LE', 'UTF8', $chr);
		}
	}
}

 

답글 남기기