Dev Blog

스크립트 & 소스코드 공유

실무에서 유용하게 쓰는 스크립트와 코드 조각을 블로그 게시판으로 저장하고 공유합니다.

PHP 한글 종성에 맞는 조사(은/는, 이/가, 을/를) 자동 변환 클래스

페이지 정보

조회 171회 작성일 20-04-29 09:43
UTF-8 한글 문자열에서 마지막 글자의 종성(받침) 유무에 따라 은/는, 이/가, 을/를, 과/와 같은 올바른 조사로 자동 치환해주는 PHP 클래스를 소개한다. 명사가 변수로 치환되는 메시지 조합 시 자연스러운 한국어 문장을 만들 수 있으며, 조사별 매핑과 종성 판단 로직이 담긴 전체 코드를 제공한다.

사용자에게 보여줄 메세지 문자열을 조합하는데,

일부 명사가 변수로 치환될 경우 치환될 단어에 따라 적절한 조사를 붙여줘야 함. (아니면 왈도체를...)

조사 바로 앞의 문자에 받침(종성)이 있냐 없냐에 따라 구분되는데,

UTF-8 이라 가정하고 종성이 있는지 없는지 판단하여 적절한 조사를 치환해주는 간단한 클래스를 만들었음.

// 게임 메세지라 가정하고 치환하는 예제
$name   = '백충덕';
$monster = '고블린';
$item1 = '포션';
$item2 = '엘릭서';

$str = '몬스터 '.$monster.'{가} 나타났다.'."\n";
$str .= $name.'{은} '.$monster.'{를} 물리치고 '.$item1.'{와} '.$item2.'{를} 얻었다.'."\n";
echo Postposition::conv($str);
// 출력
// 몬스터 고블린이 나타났다.
// 백충덕은 고블린을 물리치고 포션과 엘릭서를 얻었다.

// 조사 치환 함수
// 치환대상 조사를 {가},{은} 식으로 감싼 문자을 넘기면 알아서 변환해 줌.
class Postposition
{
// 조사 리스트
// 0,2,4,6 = 종성있음
// 1,3,5,7 = 종성없음
const POSTPOSITION_LIST = '이가은는을를과와';

// 인스턴스
private static $instance = null;

// 문장에서 조사를 적절하게 변환
public static function conv($str)
{
return self::getInstance()->__conv($str);
}

// 인스턴스 반환
private static function getInstance()
{
if (self::$instance === null) self::$instance = new self;

return self::$instance;
}

// 생성자. internal encoding 세팅
private function __construct()
{
mb_internal_encoding('UTF-8');
}

// 조사 변환
private function __conv($str)
{
return preg_replace_callback("/(.)\\{([".self::POSTPOSITION_LIST."])\\}/u", array($this, 'replace'), $str);
}

// preg_replace_callback의 callback함수
private function replace($matches)
{
// 조사 바로 앞 한글자
$lastChar = $matches[1];
// 조사
$postpositionMatched = $matches[2];

// 종성 유/무에 따른 조사배열 세팅
$arrPostposition = array(
'종성없음' => $postpositionMatched,
'종성있음' => $postpositionMatched
);
$pos = mb_strpos(self::POSTPOSITION_LIST, $postpositionMatched);
if ($pos % 2 != 0) {
$arrPostposition['종성있음'] = mb_substr(self::POSTPOSITION_LIST, $pos-1, 1);
} else {
$arrPostposition['종성없음'] = mb_substr(self::POSTPOSITION_LIST, $pos+1, 1);
}

// 기본값 = '종성있음'
$lastCharStatus = '종성있음';

// 2바이트 이상 유니코드 문자
if (strlen($lastChar) > 1) {
$code = $this->utf8Ord($lastChar) - 44032;

// 한글일 경우 (가=0, 힣=11171)
if ($code > -1 && $code < 11172) {
// 초성
//$code / 588
// 중성
//$code % 588 / 28
// 종성
if ($code % 28 == 0) $lastCharStatus = '종성없음';
}
// 1바이트 ASCII
} else {
// 숫자중 2(이),4(사),5(오),9(구)는 종성이 없음
if (strpos('2459', $lastChar) > -1) {
$lastCharStatus = '종성없음';
}
}

// 종성 상태에 알맞는 조사를 붙여 반환
return $lastChar.$arrPostposition[$lastCharStatus];
}

// ord() UTF-8 버전
private function utf8Ord($char)
{
switch (strlen($char)) {
case 1:
return ord($char);
break;
case 2:
return ((ord($char[0]) & 0x1F) << 6) | (ord($char[1]) & 0x3F);
break;
case 3:
return ((ord($char[0]) & 0x0F) << 12) | ((ord($char[1]) & 0x3F) << 6) | (ord($char[2]) & 0x3F);
break;
case 4:
return ((ord($char[0]) & 0x07) << 18) | ((ord($char[1]) & 0x3F) << 12) | ((ord($char[2]) & 0x3F) << 6) | (ord($char[3]) & 0x3F);
break;
default:
return $char;
}
}
}


Let's create something great together.

프로젝트 문의 및 견적 요청은 언제든 환영합니다.