조사 처리 클래스 추가

This commit is contained in:
2018-05-31 02:50:58 +09:00
parent 9eb35b55c6
commit 93d580e74e
2 changed files with 182 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
<?php
namespace sammo;
class JosaUtil{
// https://github.com/coxcore/postposition 의 php 버전
//TODO:한자 매핑 필요
const KO_START_CODE = 44032;
const KO_FINISH_CODE = 55203;
const REG_INVALID_CHAR = '/[^a-zA-Z0-9ㄱ-ㅎ가-힣\s]+/g';
const REG_TARGET_CHAR = '/^[\s\S]*?(\S*)\s*$/';
const PRE_REG_NORMAL_FIXED = [
"check|[hm]ook|limit",
];
const PRE_REG_SPECIAL_CHAR = [
"[ㄱ-ㄷㅁ-ㅎ036]",
"^[mn]",
"\\S[mn]e?",
"\\S(?:[aeiom]|lu)b",
"(?:u|\\S[aei]|[^o]o)p",
"(?:^i|[^auh]i|\\Su|[^ei][ae]|[^oi]o)t",
"(?:\\S[iou]|[^e][ae])c?k",
"\\S[aeiou](?:c|ng)",
"foot|go+d|b[ai]g|private",
"^(?:app|kor)",
];
const PRE_REG_SPECIAL_RO = [
"[178ㄹ]",
"^[lr]",
"^\\Sr",
"\\Sle?",
];
const DEFAULT_POSTPOSITION = [
""=> "",
""=> "",
""=> "",
"이나"=> "",
""=> "",
"으로"=> "",
];
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);
};
}
}
+27
View File
@@ -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()
}