조사 처리 클래스 추가
This commit is contained in:
@@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ namespace sammo;
|
|||||||
|
|
||||||
class StringUtil
|
class StringUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 전각, 반각 길이 기준의 substr
|
* 전각, 반각 길이 기준의 substr
|
||||||
* @param string $str 원본 문자열
|
* @param string $str 원본 문자열
|
||||||
@@ -158,4 +159,30 @@ class StringUtil
|
|||||||
'|', '{', '}', ':', '', '<', '>', '?', ' '
|
'|', '{', '}', ':', '', '<', '>', '?', ' '
|
||||||
], '', $str);
|
], '', $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()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user