한국어 분석기를 만들려고 하니 형태소 분석을 위해 음절을 자모로 분리해야 할
필요가 생겼다.
즉 "한글"을 "ㅎ" +"ㅏ"+'ㄴ"+"ㄱ"+"ㅡ"+"ㄹ" 로 분리해서 어절의 원형을 찾아야
한다. 유니코드에서 한글 음절은 AC00 ~ D7A3의 영역에 있다.
유니코드에서 한글 한 글자의 값은 다음 공식에 의해 찾을 수 있다.
코드 = AC00 + [초성번호]*588 + [중성번호]*28 + [종성번호]
이를 이용하면 초성/중성/종성을 분리해 낼 수 있다.
유니코드에서 한글과 관련된 코드는 세가지 영역으로 나누어져 있다.
1100 ~ 11FF Hangul Jamo 한글 자모
3130 ~ 318F Hangul Compatibility Jamo 호환용 한글 자모
AC00 ~ D7A3 Hangul Syllables 한글 글자 마디
이 영역의 코드값은 윈도우즈 문자표에서 확인할 수 있다.
unit Hanguel;
interface
uses
SysUtils;
const
ChoSungTbl: WideString = 'ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ';
JungSungTbl: WideString = 'ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ';
JongSungTbl: WideString = ' ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ';
UniCodeHangeulBase = $AC00;
UniCodeHangeulLast = $D79F;
type
TSyllable = class
public
class function AnsiToUnicode(const Source: AnsiString): WideString;
class function SplitJaMo(Unicode: WideChar; var ChoSung, JungSung, JongSung: WideChar): Boolean; overload;
class function SplitJaMo(const Source: WideString): WideString; overload;
// 초성, 중성, 종성을 가지고 한글자로 조합합니다
// 예) ㄱ + ㅜ + ㄹ => 굴
class function MergeJaMo(ChoSung, JungSung, JongSung: WideChar): WideChar;
end;
implementation
{ TSyllable }
class function TSyllable.AnsiToUnicode(const Source: AnsiString): WideString;
begin
// Result:= StringToWideChar(Source, Result, Length(Source)+ 1);
Result:= WideString(Source);
end;
// Unicode가 한글 음절이면 True를 그렇지 않으면 False를 돌려준다.
class function TSyllable.SplitJaMo(Unicode: WideChar; var ChoSung, JungSung,
JongSung: WideChar): Boolean;
var
Code: Cardinal;
Value, ChoSungIdx, JungSungIdx, JongSungIdx: Integer;
begin
Result:= True;
Value:= Integer(UniCode);
if (Value < UniCodeHangeulBase) or (Value > UniCodeHangeulLast) then
// (Value > (UniCodeHangeulBase + (19*588)+(21*28) + 28)) then
begin
Result:= False;
Exit;
end;
Code:= Value - UniCodeHangeulBase;
ChoSungIdx := Code div (21 * 28); // 초성 Index
Code := Code mod (21 * 28);
JungSungIdx := Code div 28; // 중성 Index
JongSungIdx := Code mod 28; // 종성 Index
ChoSung:= ChoSungTbl[ChoSungIdx + 1];
JungSung:= JungSungTbl[JungSungIdx + 1];
JongSung:= JongSungTbl[JongSungIdx + 1];
end;
class function TSyllable.MergeJaMo(ChoSung, JungSung, JongSung: WideChar): WideChar;
var
Code, ChoSungIdx, JungSungIdx, JongSungIdx: Integer;
begin
Result:= #0;
ChoSungIdx:= Pos(ChoSung, ChoSungTbl) - 1;
JungSungIdx:= Pos(JungSung, JungSungTbl) - 1;
JongSungIdx:= Pos(JongSung, JongSungTbl) - 1;
if (ChoSungIdx = -1) and (JungSungIdx = -1) and (JongSungIdx = -1) then Exit;
Code:= UniCodeHangeulBase +(ChoSungIdx * 21 + JungSungIdx) * 28 + JongSungIdx;
Result:= WideChar(Code);
end;
class function TSyllable.SplitJaMo(const Source: WideString): WideString;
var
I: Integer;
ChoSung, JungSung, JongSung: WideChar;
begin
Result:= '';
if Source = '' then Exit;
for i := 1 to Length(Source) do
begin
if not SplitJaMo(Source[I], ChoSung, JungSung, JongSung) then
Result:= Result + Source[I]
else Result:= Result + ChoSung + JungSung + JongSung;
end;
end;
end.