From 93d580e74e05d4df4de6d80b17bb3e73b04c089d Mon Sep 17 00:00:00 2001 From: hide_d Date: Thu, 31 May 2018 02:50:58 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A1=B0=EC=82=AC=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sammo/JosaUtil.php | 155 +++++++++++++++++++++++++++++++++++++++ src/sammo/StringUtil.php | 27 +++++++ 2 files changed, 182 insertions(+) create mode 100644 src/sammo/JosaUtil.php diff --git a/src/sammo/JosaUtil.php b/src/sammo/JosaUtil.php new file mode 100644 index 00000000..454567d6 --- /dev/null +++ b/src/sammo/JosaUtil.php @@ -0,0 +1,155 @@ + "는", + "이"=> "가", + "과"=> "와", + "이나"=> "나", + "을"=> "를", + "으로"=> "로", + ]; + + private static $regNormalFixed; + private static $regSpecialChar; + private static $regSpecialRo; + + private static $mapPostPosition; + + private static $init = false; + + private static function init(){ + if(JosaUtil::$init){ + return; + } + + JosaUtil::$init = true; + JosaUtil::$regNormalFixed = '/(?:'.join('|', JosaUtil::PRE_REG_NORMAL_FIXED).')$/i'; + JosaUtil::$regSpecialChar = '(?:'.join('|', JosaUtil::PRE_REG_SPECIAL_CHAR).')$/i'; + JosaUtil::$regSpecialRo = '/(?:'.join('|', JosaUtil::PRE_REG_SPECIAL_RO).')$/i'; + + $mapPostPosition = []; + + foreach(JosaUtil::DEFAULT_POSTPOSITION as $key=>$val){ + $mapPostPosition["($key)$val"]=$key; + $mapPostPosition[$key]=$key; + $mapPostPosition[$val]=$key; + } + JosaUti::$mapPostPosition = $mapPostPosition; + + } + + private static function checkText(string $text, bool $isRo){ + JosaUtil::init(); + if(preg_match(JosaUtil::$regNormalFixed, $text)){ + return false; + } + + if(preg_match(JosaUtil::$regSpecialChar, $text)){ + return true; + } + + if(!$isRo && preg_match(JosaUtil::$regSpecialRo, $text)){ + return true; + } + + return false; + } + + private static function checkCode(int $code, bool $isRo){ + JosaUtil::init(); + $jongsung = ($code - JosaUtil::KO_START_CODE) % 28; + + if($jongsung === 0){ + return false; + } + + if($isRo && $jongsung === 8){ + return false; + } + + return false; + } + + public static function check(string $text, string $type=''){ + JosaUtil::init(); + + $target = preg_replace(JosaUtil::REG_INVALID_CHAR, ' ', $text); + $target = preg_replace(JosaUtil::REG_TARGET_CHAR, '$1', $target); + $code = StringUtil::splitString($target); + $code = StringUtil::uniord($code[count($code)-1]); + + $isKorean = (JosaUtil::KO_START_CODE <= $code && $code <= JosaUtil::KO_FINISH_CODE); + $isRo = ($type == '으로' || $type == '로'); + + return $isKorean ? JosaUtil::checkCode($code, $isRo) : JosaUtil::checkText($text, $isRo); + } + + public static function pick(string $text, string $type, string $noJongsung=''){ + /* NOTE:원본 코드와 인자 순서가 다름. + * 원본은 pick('바람', '랑', '이랑'); 이었다면 JosaUtil::pick('바람', '이랑', '랑'); 으로 바뀜. + * JosaUtil::pick('바람', '은', '는'); JosaUti::pick('바람', '이', '가');처럼 쓰기 위해서임. + */ + JosaUtil::init(); + + if(!$noJongsung){ + if(!key_exists($type, JosaUtil::$mapPostPosition)){ + throw new \InvalidArgumentException('올바르지 않은 조사 지정'); + } + $type = JosaUtil::$mapPostPosition[$type]; + $noJongsung = JosaUtil::DEFAULT_POSTPOSITION[$type]; + } + + return JosaUtil::check($text, $type)?$type:$noJongsung; + } + + public static function put(string $text, string $type, string $noJongsung=''){ + return $text.JosaUtil::pick($text, $type, $noJongsung); + } + + public static function fix(string $type, string $noJongsung=''){ + JosaUtil::init(); + + if(!$noJongsung){ + if(!key_exists($type, JosaUtil::$mapPostPosition)){ + throw new \InvalidArgumentException('올바르지 않은 조사 지정'); + } + $type = JosaUtil::$mapPostPosition[$type]; + $noJongsung = JosaUtil::DEFAULT_POSTPOSITION[$type]; + } + + return function(string $text) use ($type, $noJongsung) { + return JosaUtil::put($text, $type, $noJongsung); + }; + } +} \ No newline at end of file diff --git a/src/sammo/StringUtil.php b/src/sammo/StringUtil.php index 30d4e9a8..daf32e86 100644 --- a/src/sammo/StringUtil.php +++ b/src/sammo/StringUtil.php @@ -3,6 +3,7 @@ namespace sammo; class StringUtil { + /** * 전각, 반각 길이 기준의 substr * @param string $str 원본 문자열 @@ -158,4 +159,30 @@ class StringUtil '|', '{', '}', ':', '', '<', '>', '?', ' ' ], '', $str); } + + public static function uniord(string $c) { + if (ord($c{0}) >=0 && ord($c{0}) <= 127) + return ord($c{0}); + if (ord($c{0}) >= 192 && ord($c{0}) <= 223) + return (ord($c{0})-192)*64 + (ord($c{1})-128); + if (ord($c{0}) >= 224 && ord($c{0}) <= 239) + return (ord($c{0})-224)*4096 + (ord($c{1})-128)*64 + (ord($c{2})-128); + if (ord($c{0}) >= 240 && ord($c{0}) <= 247) + return (ord($c{0})-240)*262144 + (ord($c{1})-128)*4096 + (ord($c{2})-128)*64 + (ord($c{3})-128); + if (ord($c{0}) >= 248 && ord($c{0}) <= 251) + return (ord($c{0})-248)*16777216 + (ord($c{1})-128)*262144 + (ord($c{2})-128)*4096 + (ord($c{3})-128)*64 + (ord($c{4})-128); + if (ord($c{0}) >= 252 && ord($c{0}) <= 253) + return (ord($c{0})-252)*1073741824 + (ord($c{1})-128)*16777216 + (ord($c{2})-128)*262144 + (ord($c{3})-128)*4096 + (ord($c{4})-128)*64 + (ord($c{5})-128); + if (ord($c{0}) >= 254 && ord($c{0}) <= 255) // error + return FALSE; + return 0; + } + + public static function unichr(int $o) { + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding('&#'.intval($o).';', 'UTF-8', 'HTML-ENTITIES'); + } else { + return chr(intval($o)); + } + } // function _unichr() }