LCL Unicode Support/ko: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: LCL Unicode Support/ko
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## 소개 | |
| 2 | + | ||
| 3 | + | 0.9.25 에서 라자루스는 Gtk1을 제외한 모든 플랫폼에서 유니코드를 완전하게 지원하게 되었다. 이 페이지는 FPC 2.6.4를 사용하는 라자루스 1.4 까지의 유니코드에 대해 다룬다. 2.0을 시작하면서 라자루스는 FPC 3.0+의 특징을 사용하여 유니코드 지원을 개선하였다. 자세한 내용은 다음을 보시길 : [[Unicode Support in Lazarus|라자루스에서 개선 된 유니코드 지원]] | |
| 4 | + | ||
| 5 | + | ## 사용자를 위한 지침 | |
| 6 | + | ||
| 7 | + | 라자루스가 유니코드 위젯 세트를 가지고 있다지만 모든 것이 유니코드가 아니란 것을 알아야 한다. 문자열 인코딩의 시작이 무엇인지 알고 다른 인코딩을 필요로하는 라이브러리간에 적절히 인코딩하는 것은 개발자의 책임이다. | |
| 8 | + | ||
| 9 | + | 보통 인코딩은 라이브러리 단위로 이루어진다(예를 들면, 동적 라이브러리인 DLL이나 라자루스 패키지). 각 라이브러리는 한 종류의 인코딩만을 요구하고, 이것들은 대개 Unicode(라자루스에서는 UTF-8) 또는 ANSI 이다(이것은 실제로는 시스템 인코딩으로 UTF-8 이거나 아니라는 뜻이다). 2.6 이하의 FPC의 RTL 과 FCL 은 ANSI 문자열이 필요하다. | |
| 10 | + | ||
| 11 | + | 유니코드와 ANSI는 다음 코드를 사용하여 변환할 수 있다. | |
| 12 | + | ||
| 13 | + | - **UTF8ToAnsi** 와 **AnsiToUTF8**은 (FPC) System 유닛에서 기능한다. | |
| 14 | + | - 또는 **UTF8ToSys** 와 **SysToUTF8**은 (Lazarus) FileUtil 유닛에서 기능한다. | |
| 15 | + | ||
| 16 | + | 두번째 것이 더 빠르고 산뜻하지만 더 많은 코드가 프로그램에 들어가게 된다. | |
| 17 | + | ||
| 18 | + | - FileUtil:UTF8ToSys 에서 LazUTF8:UTF8ToSys 로 변경되었다. \[1.8.2버전\] | |
| 19 | + | ||
| 20 | + | ### FPC 는 유니코드를 알고 있지 않다 | |
| 21 | + | ||
| 22 | + | 현재의 FPC버전(2.6.x 이하)에서 프리파스칼 런타임 라이브러리(RTL)과 프리파스칼 컴포넌트 라이브러리(FCL)은 ANSI라서 유니코드 라이브러리에서 가져오거나 유니코드 라이브러리로 보내는(예, LCL) 경우에는 문자열 변환이 필요하다. | |
| 23 | + | ||
| 24 | + | String 을 포함하여 FPC 2.7.1 계열의 개발 버전에 중요한 개선점들이 있다. RawByteString 과 UTF8String 에 대해서는 [[FPC Unicode support|FPC의 유니코드 지원]] 을 보세요. | |
| 25 | + | ||
| 26 | + | ### ANSI 와 Unicode 간의 변환 | |
| 27 | + | ||
| 28 | + | > **Note:** AnsiToUTF8 와 UTF8ToAnsi 는 리눅스, BSD, Mac OS X 에서 사용할 경우 widestring 관리자가 필요하다. SysToUTF8 과 UTF8ToSys 함수를 사용할 수 있다.(unit FileUtil) 또는 프로그램이 사용하는 첫번째 uses 섹션에 cwstring을 추가하여 widestring 매니저를 추가할 수 있게된다. | |
| 29 | + | ||
| 30 | + | 예: | |
| 31 | + | ||
| 32 | + | TEdit에서 문자열을 얻고 어떤 RTL 파일 루틴에 문자열을 보내고 싶다고 하자. | |
| 33 | + | ||
| 34 | + | ``` pascal | |
| 35 | + | var | |
| 36 | + | MyString: string; // utf-8 로 인코드 되어 있다. | |
| 37 | + | begin | |
| 38 | + | MyString := MyTEdit.Text; | |
| 39 | + | SomeRTLRoutine(UTF8ToAnsi(MyString)); | |
| 40 | + | end; | |
| 41 | + | ``` | |
| 42 | + | ||
| 43 | + | 반대로 보낼 경우에는: | |
| 44 | + | ||
| 45 | + | ``` pascal | |
| 46 | + | var | |
| 47 | + | MyString: string; // ANSI 로 인코드 되어 있다. | |
| 48 | + | begin | |
| 49 | + | MyString := SomeRTLRoutine; | |
| 50 | + | MyTEdit.Text := AnsiToUTF8(MyString); | |
| 51 | + | end; | |
| 52 | + | ``` | |
| 53 | + | ||
| 54 | + | ### Widestrings 과 Ansistrings | |
| 55 | + | ||
| 56 | + | widestring 은 2-바이트 크기의 요소를 가지는 기본 데이터의 문자열 타입이다. Widestring은 거의 대부분 UTF-16 로 인코딩된 데이터를 가진다. [[Widestrings|widestring]] 을 보세요 | |
| 57 | + | ||
| 58 | + | Widestring의 배열로 억세스할 수 있는 각 데이터 포인트는 2 바이트를 가지며, UTF-16에서 문자(character)는 1 또는 2 데이터 포인트일 수 있어서, 2 또는 4 바이트를 차지할 수 있다. 이는 Widestring을 배열로 접근하고 이러한 방법으로 UTF-16 문자들을 얻으려고 하는 것은 **확실히 잘못된 것**이어서 문자열에 4 바이트 문자가 들어있을 때는 실패하게 될 것이다. 또한 UTF-8 과 마찬가지로 UTF-16은 분리되는 문자를 가질 수도 있다. 예를 들어 문자 "Á" 는 단일 문자로 인코드할 수 있거나 두개의 문자로 인코드 될 수도 있다: "A" + 수정 액센트. 그러므로 Unicode에서 엑센트 문자를 가진 문장은 다양한 방법으로 인코딩 될 수 있어서 라자루스나 FPC는 자동으로 이들을 다룰 수가 없다. | |
| 59 | + | ||
| 60 | + | Ansistrings 를 Widestrings 로 전달할 때 인코딩을 변환해야 한다. | |
| 61 | + | ||
| 62 | + | ``` pascal | |
| 63 | + | var | |
| 64 | + | w: widestring; | |
| 65 | + | begin | |
| 66 | + | w:='Über'; // 틀림, FPC 는 시스템 코드페이지를 UTF16 로 변경할 것이다. | |
| 67 | + | w:=UTF8ToUTF16('Über'); // 맞음 | |
| 68 | + | Button1.Caption:=UTF16ToUTF8(w); | |
| 69 | + | end; | |
| 70 | + | ``` | |
| 71 | + | ||
| 72 | + | ### UTF8 문자열 과 문자들 | |
| 73 | + | ||
| 74 | + | Lazarus 0.9.30 까지 UTF-8 핸들링 루틴은 LCLProc 유닛 내의 LCL에 있었다. 라자루스 0.9.31+에서 LCLProc 내의 루틴들은 여전히 호환성 문제 때문에 쓸모가 있으나 UTF-8을 다루는 실제코드는 lazutf8 유닛내의 lazutils 패키지에 있다. UTF-8 문자열상에서 실행하기 위해서는 프리파스칼에서 온 SysUtils 루틴 대신에 lazutf8 유닛에 있는 루틴을 사용하는게 좋은데 이는, SysUtils 은 유니코드를 다룰 준비가 되어있지 않으나, lazutf8은 사용할 준비가 되어있기 때문이다. 간단히 Sysutils의 루틴을 lazutf8에 있는 같은 루틴으로 바꾸면 되는데 UTF8 선행사가 붙은 것을 제외하고는 이름이 같기 때문이다. | |
| 75 | + | ||
| 76 | + | #### UTF-8 String Copy, Length, LowerCase, 등등 | |
| 77 | + | ||
| 78 | + | UTF-8문자열로 실행하기 원하는 거의 모든 동작들은 lazutf 유닛의 루틴으로 대치할 수 있다.(라자루스 0.9.30 이상에서는 LCLProc 유닛) 다음과 같이 lazurf8.pas 에서 나온 루틴의 리스트를 보세요 | |
| 79 | + | ||
| 80 | + | ``` pascal | |
| 81 | + | function UTF8CharacterLength(p: PChar): integer; // 문자의 길이 | |
| 82 | + | function UTF8Length(const s: string): PtrInt; // 문자열의 길이 | |
| 83 | + | function UTF8Length(p: PChar; ByteCount: PtrInt): PtrInt; | |
| 84 | + | function UTF8CharacterToUnicode(p: PChar; out CharLen: integer): Cardinal; | |
| 85 | + | function UnicodeToUTF8(u: cardinal; Buf: PChar): integer; inline; | |
| 86 | + | function UnicodeToUTF8SkipErrors(u: cardinal; Buf: PChar): integer; | |
| 87 | + | function UnicodeToUTF8(u: cardinal): shortstring; inline; | |
| 88 | + | function UTF8ToDoubleByteString(const s: string): string; | |
| 89 | + | function UTF8ToDoubleByte(UTF8Str: PChar; Len: PtrInt; DBStr: PByte): PtrInt; | |
| 90 | + | function UTF8FindNearestCharStart(UTF8Str: PChar; Len: integer; | |
| 91 | + | BytePos: integer): integer; | |
| 92 | + | // n-번째 UTF8 문자를 찿으며, BIDI 는 무시한다. | |
| 93 | + | function UTF8CharStart(UTF8Str: PChar; Len, CharIndex: PtrInt): PChar; | |
| 94 | + | // n-번째 UTF8 문자릐 바이트 인덱스를 찾되, BIDI (substr 의 바이트 길이)는 무시한다. | |
| 95 | + | function UTF8CharToByteIndex(UTF8Str: PChar; Len, CharIndex: PtrInt): PtrInt; | |
| 96 | + | procedure UTF8FixBroken(P: PChar); | |
| 97 | + | function UTF8CharacterStrictLength(P: PChar): integer; | |
| 98 | + | function UTF8CStringToUTF8String(SourceStart: PChar; SourceLen: PtrInt) : string; | |
| 99 | + | function UTF8Pos(const SearchForText, SearchInText: string): PtrInt; | |
| 100 | + | function UTF8Copy(const s: string; StartCharIndex, CharCount: PtrInt): string; | |
| 101 | + | procedure UTF8Delete(var s: String; StartCharIndex, CharCount: PtrInt); | |
| 102 | + | procedure UTF8Insert(const source: String; var s: string; StartCharIndex: PtrInt); | |
| 103 | + | ||
| 104 | + | function UTF8LowerCase(const AInStr: string; ALanguage: string=''): string; | |
| 105 | + | function UTF8UpperCase(const AInStr: string; ALanguage: string=''): string; | |
| 106 | + | function FindInvalidUTF8Character(p: PChar; Count: PtrInt; | |
| 107 | + | StopOnNonASCII: Boolean = false): PtrInt; | |
| 108 | + | function ValidUTF8String(const s: String): String; | |
| 109 | + | ||
| 110 | + | procedure AssignUTF8ListToAnsi(UTF8List, AnsiList: TStrings); | |
| 111 | + | ||
| 112 | + | //비교 함수 | |
| 113 | + | ||
| 114 | + | function UTF8CompareStr(const S1, S2: string): Integer; | |
| 115 | + | function UTF8CompareText(const S1, S2: string): Integer; | |
| 116 | + | ``` | |
| 117 | + | ||
| 118 | + | ### 디렉토리 및 파일 이름 다루기 | |
| 119 | + | ||
| 120 | + | 라자루스는 UTF-인코딩에서 파일명과 디렉토리명을 제외하고 조절 또는 동작하지만, RTL은 디렉토리 및 파일명에서는 ANSI 스트링을 사용한다. | |
| 121 | + | ||
| 122 | + | 예를 들면, TFileListBox 의 디렉토리 속성을 현재 디렉토리로 설정하는 버튼을 놓아보자. RTL 함수 [[doc:rtl/sysutils/getcurrentdir.html|GetCurrentDir]] 는 ANSI로 Unicode가 아니므로 변환이 필요하다. | |
| 123 | + | ||
| 124 | + | ``` pascal | |
| 125 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 126 | + | begin | |
| 127 | + | FileListBox1.Directory:=SysToUTF8(GetCurrentDir); | |
| 128 | + | // 또는 FileUtil 유닛의 함수를 사용하거나 | |
| 129 | + | FileListBox1.Directory:=GetCurrentDirUTF8; | |
| 130 | + | end; | |
| 131 | + | ``` | |
| 132 | + | ||
| 133 | + | FileUtil 유닛은 UTF-8 문자열에 관한 공통 파일들을 정의하고 있다. | |
| 134 | + | ||
| 135 | + | ``` pascal | |
| 136 | + | // RTL 과 유사하지만 시스템 인코딩 대신 UTF-8 로 동작하는 기본 함수들 | |
| 137 | + | ||
| 138 | + | // AnsiToUTF8 과 UTF8ToAnsi 은 Linux, BSD, Mac OS X에서는 widestring 매니저가 필요하다. | |
| 139 | + | // 하지만 이 OS들은 UTF-8 이 기본 시스템 인코딩이기 때문에 widestring 매니저가 필요하지는 않다. | |
| 140 | + | function NeedRTLAnsi: boolean;// 시스템 인코딩이 UTF-8이 아니면 true | |
| 141 | + | procedure SetNeedRTLAnsi(NewValue: boolean); | |
| 142 | + | function UTF8ToSys(const s: string): string;// UTF8ToAnsi 와 같으나 widestring 매니저에 보다 더 독립적이다 | |
| 143 | + | function SysToUTF8(const s: string): string;// AnsiToUTF8 과 같으나 widestring 매니저에 보다 더 독립적이다 | |
| 144 | + | ||
| 145 | + | // 파일 동작 | |
| 146 | + | function FileExistsUTF8(const Filename: string): boolean; | |
| 147 | + | function FileAgeUTF8(const FileName: string): Longint; | |
| 148 | + | function DirectoryExistsUTF8(const Directory: string): Boolean; | |
| 149 | + | function ExpandFileNameUTF8(const FileName: string): string; | |
| 150 | + | function ExpandUNCFileNameUTF8(const FileName: string): string; | |
| 151 | + | {$IFNDEF VER2_2_0} | |
| 152 | + | function ExtractShortPathNameUTF8(Const FileName : String) : String; | |
| 153 | + | {$ENDIF} | |
| 154 | + | function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec): Longint; | |
| 155 | + | function FindNextUTF8(var Rslt: TSearchRec): Longint; | |
| 156 | + | procedure FindCloseUTF8(var F: TSearchrec); | |
| 157 | + | function FileSetDateUTF8(const FileName: String; Age: Longint): Longint; | |
| 158 | + | function FileGetAttrUTF8(const FileName: String): Longint; | |
| 159 | + | function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint; | |
| 160 | + | function DeleteFileUTF8(const FileName: String): Boolean; | |
| 161 | + | function RenameFileUTF8(const OldName, NewName: String): Boolean; | |
| 162 | + | function FileSearchUTF8(const Name, DirList : String): String; | |
| 163 | + | function FileIsReadOnlyUTF8(const FileName: String): Boolean; | |
| 164 | + | function GetCurrentDirUTF8: String; | |
| 165 | + | function SetCurrentDirUTF8(const NewDir: String): Boolean; | |
| 166 | + | function CreateDirUTF8(const NewDir: String): Boolean; | |
| 167 | + | function RemoveDirUTF8(const Dir: String): Boolean; | |
| 168 | + | function ForceDirectoriesUTF8(const Dir: string): Boolean; | |
| 169 | + | ||
| 170 | + | // 환경 | |
| 171 | + | function ParamStrUTF8(Param: Integer): string; | |
| 172 | + | function GetEnvironmentStringUTF8(Index : Integer): String; | |
| 173 | + | function GetEnvironmentVariableUTF8(const EnvVar: String): String; | |
| 174 | + | function GetAppConfigDirUTF8(Global: Boolean): string; | |
| 175 | + | ``` | |
| 176 | + | ||
| 177 | + | ### 윈도우에서 동아시아 언어 들 | |
| 178 | + | ||
| 179 | + | 윈도우즈 XP 상의 사용자 인터페이스 컨트롤의 기본 폰트 (Tahoma)는 여러 스크립트/알파벳/언어들을 정확히 표시할 수 있다. 이 언어에는 아라비아, 러시아(Cyrillic 알파벳) 과 서양 언어(라틴/그리스 알파벳)이 해당되며, 한국어, 중국어, 일본어 같은 동아시아 언어는 해당되지 않는다. | |
| 180 | + | ||
| 181 | + | 간단하게 제어판으로가서 지역 설정을 선택하고, 언어 탭을 클릭하고 동아시아 언어팩을 설치하면, 표준 사용자 인터페이스 폰트는 이 언어들을 정확히 표현할 수 있다.이러한 언어에 지역특성화 된 윈도우즈 XP 버전은 이 언어팩을 이마 설치하고 있다. 더 많은 설명은 [여기에](http://newton.uor.edu/Departments&Programs/AsianStudiesDept/Language/asianlanguageinstallation_XP.html) | |
| 182 | + | ||
| 183 | + | 이후의 윈도우즈 버전은 이 언어에 대한 지원을 하고 있다. | |
| 184 | + | ||
| 185 | + | ### UTF-8의 사용 | |
| 186 | + | ||
| 187 | + | 자세한 것은 [[UTF8 strings and characters|UTF-8 문자열과 문자를]] 보세요 | |
| 188 | + | ||
| 189 | + | ## Free Pascal Particularities | |
| 190 | + | ||
| 191 | + | ### UTF8 와 소스 파일 - the missing BOM | |
| 192 | + | ||
| 193 | + | 라자루스로 소스파일을 만들거나 비-ASCII 문자들을 사용하면 파일은 UTF-8로 저장된다. 이것은 **BOM** (Byte Order Mark)을 사용하지 **않는다**. 소스 에디터 상에서 오른쪽 마우스 클릭하여 / File Settings / Encoding 을 선택하여 인코딩을 설정할 수 있다. UTF-8이 BOM을 갖지 않는 것과는 별도로, BOM이 없는 것은 FPC 가 Ansistring을 다루는 방법 때문이다. 호환성 때문에 LCL은 Ansistring 을 사용하고 이식성 때문에 LCL은 UTF8을 사용한다. | |
| 194 | + | ||
| 195 | + | Note: 어떤 MS 윈도우즈 텍스트 에디터는 이 파일들을 시스템 코드페이지(OEM 코드페이지)로 인코드하고 부정확한 문자로 표시한다. **BOM 을 추가하면 안된다** 만약 BOM을 추가했다면 모든 문자열 할당을 변경해야만 한다. | |
| 196 | + | ||
| 197 | + | 예를 들면: | |
| 198 | + | ||
| 199 | + | ``` pascal | |
| 200 | + | Button1.Caption := 'Über'; | |
| 201 | + | ``` | |
| 202 | + | ||
| 203 | + | BOM 이 없다면 (그리고 코드페이지를 모른다면) 컴파일러는 문자열을 시스템 인코딩으로 다루고 각 바이트를 변환없이 문자열로 복사한다. 이것이 LCL이 문자열을 요구하는 방법이다. | |
| 204 | + | ||
| 205 | + | ``` pascal | |
| 206 | + | // 소스파일은 BOM이 없이 UTF 로 저장 | |
| 207 | + | if FileExists('Über.txt') then ; // 잘못 됨, FileExists 는 시스템 인코딩을 필요로 함 | |
| 208 | + | if FileExistsUTF8('Über.txt') then ; // 맞음 | |
| 209 | + | ``` | |
| 210 | + | ||
| 211 | + | ## Unicode essentials | |
| 212 | + | ||
| 213 | + | Unicode 표준은 정수 0부터 10FFFF(h) 까지 문자들에 매핑한다. 각 매핑은 코드포인트라고 부른다. 다른말로 말하면, Unicode 문자는 다른 말로 말하면 원칙적으로 코드 포인트는 U+000000 에서 U+10FFFF (0에서 1 114 111) 까지로 정의한다. | |
| 214 | + | ||
| 215 | + | Unicode 코드 포인트를 유일한 바이트 순서로 표현하는데는 세가지 방법이 있다. 이 방법들은 유니코드 변환 포맷이라고 부르다: UTF-8, UTF-16 및 UTF-32. 이들간에는 모두 변환이 가능하다. 다음에 기초적인 특성을 보여주었다. | |
| 216 | + | ||
| 217 | + | ` UTF-8 UTF-16 UTF-32`\ | |
| 218 | + | `가장 작은 코드 포인트 [hex] 000000 000000 000000`\ | |
| 219 | + | `가장 큰 토드 포인트 [hex] 10FFFF 10FFFF 10FFFF`\ | |
| 220 | + | `코드 단위 크기 [bits] 8 16 32`\ | |
| 221 | + | `문자당 최소 바이트 수 1 2 4`\ | |
| 222 | + | `문자당 최대 바이트 수 4 4 4` | |
| 223 | + | ||
| 224 | + | **UTF-8**은 몇가지 중요하고도 유용한 특징이 있다: 이것은 바이트의 순서로 번역 되므로 lo- 와 hi-순서 바이트라는 개념이 없다. U+000 에서 U+007E(ASCII)의 유니코드 문자는 00h에서 7Fh(아스키 호환성)로 간단히 인코드 된다. 7-비트 아스키 문자들을 가진 화일과 문자들은 아스키와 UTF-8에서 모두 같은 인코등을 갖는 다는 것을 의미한다. U+007F를 넘는 모든 문자들은 몇개 바이트의 순서로 인코딩 되어 각각은 두개의 MSB 셋트를 가지게 된다. 더 긴 바이트의 다른 문자에서는 문자의 바이트 순서가 있는 바이트를 얻을 수 있다. 이것은 부분 문자열을 쉽게 검색할 수 있도록 한다. 멀티 바이트(비-아스키 문자를 말함) 중 첫번째는 항상 C0h에서 FDh 사이이며 이것은 이 문자에 대해 얼마나 많은 바이트가 가능한지를 표시하는 것이다. 멀티바이트 순서에서 모든 다른 바이트는 80h에서 BFh 사이에 있어 쉽게 동기화할 수 있게 한다. | |
| 225 | + | ||
| 226 | + | **UTF-16** 은 다음과 같은 중요한 속성이 있다: 이는 U+0000에서 U+d7ff까지의 단일한 16-비트 워드를 인코딩에 사용하고 나머지 유니코드 문자를 인코딩하기 위해 16-비트 워드 쌍을 사용한다. | |
| 227 | + | ||
| 228 | + | 마지막으로 모든 유니코드 문자는 **UTF-32**에서 단일한 4 바이트/32-비트 유닛으로 표시할 수 있다. | |
| 229 | + | ||
| 230 | + | 더 자세히 보기: [Unicode FAQ - Basic questions](http://www.unicode.org/faq/basic_q.html), [Unicode FAQ - UTF-8, UTF-16, UTF-32 & BOM](http://www.unicode.org/faq/utf_bom.html), [Wikipedia: UTF-8](http://en.wikipedia.org/wiki/UTF-8) [1](http://en.wikipedia.org/wiki/ISO-8859) | |
| 231 | + | ||
| 232 | + | # 상세한 구현 | |
| 233 | + | ||
| 234 | + | ## 라자루스/LCL 은 보통 UTF-8만 사용한다 | |
| 235 | + | ||
| 236 | + | 라자루스 0.9.31에서 GTK1 인터페이스에서는 톡특해서 루틴에서 다른 인코딩을 사용할 수 있는 표시를 하지 않았다면, 모든 LCL 인터페이스는 Unicode가 가능하고 LCL을 사용하며 UTF-8로 인코드 된 문자열만 사용할 수 있다. | |
| 237 | + | ||
| 238 | + | ## win32 인터페이스에서 Unicode를 가능하게 하기 | |
| 239 | + | ||
| 240 | + | ### 개관 | |
| 241 | + | ||
| 242 | + | 무선 가장 중요한 것은 Win32 인터페이스로 패치된 모든 유니코드는 IFDEF WindowsUnicodeSupport 로 끝나야 ANSI 인터페이스가 깨지는 것을 피할 수 있다. 이렇게 안정화 된 후, 모든 ifdefs는 제거되면 Unicode 부분만 남게 될 것이다. 이 싯점에서 ANSI 문자를 사용하는 모든 프로그램은 Unicode로의 이전이 필요하다. | |
| 243 | + | ||
| 244 | + | ### Win9x 상에서 Unicode 미지원 | |
| 245 | + | ||
| 246 | + | Win 9x 이하의 윈도우즈 플랫폼은 ISO 코드 페이지 표준에 기초를 두었기 때문에 유니코드를 부분적으로만 지원할 뿐이다. Windows NT로 윈도우즈 플랫폼 (예, windows 200, XP, Vista, 7, 8) 및 Windows CE는 Unicode를 모두 지원한다. Win 9x 와 NT는 두가지의 API함수를 나란히 지원한다: 이전의 ANSI 가 가능한 *A 와 새로운 Unicode 가 가능한 *W. *W 함수는 wide string을 - UTF-16인코딩 문자열 - 파라메터로 받아들인다. | |
| 247 | + | ||
| 248 | + | Windows 9x 는 모든 *W 함수를 가지지만 모두 빈 함수 뿐이어서 할 수 있는 것이 없다. 단지 몇개의 *W 함수만이 9x에서 구현되어 있을 뿐이다: 이 들은 다음 섹션인 "Windows 9x에 존재하는 Wide 함수" 에 리스트하였다. 이 속성은 하나의 어플리케이션이 Win9x 와 WinNT 에서 동작할 수 있게 하며 사용할 수 있는 API셋을 실행 시에 찾을 수 있게 한다. | |
| 249 | + | ||
| 250 | + | Windows CE는 Wide API 함수만을 지원한다. | |
| 251 | + | ||
| 252 | + | ### Wide 함수들이 Windows 9x상에 존재한다 | |
| 253 | + | ||
| 254 | + | 몇몇 Wide API 함수가 윈도우즈 9x상에 존재한다. 다음에 그 함수에 관한 리스트가 있다: <http://support.microsoft.com/kb/210341> | |
| 255 | + | ||
| 256 | + | 변환 예: | |
| 257 | + | ||
| 258 | + | ``` pascal | |
| 259 | + | GetTextExtentPoint32(hdcNewBitmap, LPSTR(ButtonCaption), | |
| 260 | + | Length(ButtonCaption), TextSize); | |
| 261 | + | ``` | |
| 262 | + | ||
| 263 | + | 이렇게: | |
| 264 | + | ||
| 265 | + | ``` pascal | |
| 266 | + | {$ifdef WindowsUnicodeSupport} | |
| 267 | + | GetTextExtentPoint32W(hdcNewBitmap, PWideChar(Utf8Decode(ButtonCaption)), Length(WideCaption), TextSize); | |
| 268 | + | {$else} | |
| 269 | + | GetTextExtentPoint32(hdcNewBitmap, LPSTR(ButtonCaption), Length(ButtonCaption), TextSize); | |
| 270 | + | {$endif} | |
| 271 | + | ``` | |
| 272 | + | ||
| 273 | + | #### Ansi 와 Wide 버전을 필요로 하는 함수들 | |
| 274 | + | ||
| 275 | + | 첫 변환 예: | |
| 276 | + | ||
| 277 | + | ``` pascal | |
| 278 | + | function TGDIWindow.GetTitle: String; | |
| 279 | + | var | |
| 280 | + | l: Integer; | |
| 281 | + | begin | |
| 282 | + | l := Windows.GetWindowTextLength(Handle); | |
| 283 | + | SetLength(Result, l); | |
| 284 | + | Windows.GetWindowText(Handle, @Result[1], l); | |
| 285 | + | end; | |
| 286 | + | ``` | |
| 287 | + | ||
| 288 | + | 이렇게: | |
| 289 | + | ||
| 290 | + | ``` pascal | |
| 291 | + | function TGDIWindow.GetTitle: String; | |
| 292 | + | var | |
| 293 | + | l: Integer; | |
| 294 | + | AnsiBuffer: string; | |
| 295 | + | WideBuffer: WideString; | |
| 296 | + | begin | |
| 297 | + | ||
| 298 | + | {$ifdef WindowsUnicodeSupport} | |
| 299 | + | ||
| 300 | + | if UnicodeEnabledOS then | |
| 301 | + | begin | |
| 302 | + | l := Windows.GetWindowTextLengthW(Handle); | |
| 303 | + | SetLength(WideBuffer, l); | |
| 304 | + | l := Windows.GetWindowTextW(Handle, @WideBuffer[1], l); | |
| 305 | + | SetLength(WideBuffer, l); | |
| 306 | + | Result := Utf8Encode(WideBuffer); | |
| 307 | + | end | |
| 308 | + | else | |
| 309 | + | begin | |
| 310 | + | l := Windows.GetWindowTextLength(Handle); | |
| 311 | + | SetLength(AnsiBuffer, l); | |
| 312 | + | l := Windows.GetWindowText(Handle, @AnsiBuffer[1], l); | |
| 313 | + | SetLength(AnsiBuffer, l); | |
| 314 | + | Result := AnsiToUtf8(AnsiBuffer); | |
| 315 | + | end; | |
| 316 | + | ||
| 317 | + | {$else} | |
| 318 | + | ||
| 319 | + | l := Windows.GetWindowTextLength(Handle); | |
| 320 | + | SetLength(Result, l); | |
| 321 | + | Windows.GetWindowText(Handle, @Result[1], l); | |
| 322 | + | ||
| 323 | + | {$endif} | |
| 324 | + | ||
| 325 | + | end; | |
| 326 | + | ``` | |
| 327 | + | ||
| 328 | + | ### 스크린 샷 | |
| 329 | + | ||
| 330 | + | <figure> | |
| 331 | + | <img src="Lazarus_Unicode_Test.png" title="Lazarus_Unicode_Test.png" /> | |
| 332 | + | <figcaption>Lazarus_Unicode_Test.png</figcaption> | |
| 333 | + | </figure> | |
| 334 | + | ||
| 335 | + | # FPC 코드 페이지 | |
| 336 | + | ||
| 337 | + | 컴파일러 (FPC)는 명령어 옵션 *-Fc*(에를 들면, *-Fcutf8*) 및 동일한 표현인 *codepage* 지시어(예, *{\$codepage utf8}*)을 소스 코드에 넣어 코드페이지를 지정하는 것을 지원한다. 이런 경우, 프로그램에서 문자열 상수를 표현하는 바이트를 문자 그대로 복사하기 보다는 컴파일러가 코드페이지에 따라 모든 문자 데이터를 해석하도록 하는 것이 좋다. | |
| 338 | + | ||
| 339 | + | 두가지 가 있다: | |
| 340 | + | ||
| 341 | + | - 유닉스 플랫폼에서, uses 절에 *swstring*을 추가하여 widestring 매니저를 포함했는지 확인하고, 없다면 프로그램은 실행시 모든 문자 데이터를 정확히 변환할 수 없을 것이다. 유닛이 프로그램이 libc에 종속되게 했을 것이기 때문에 이것이 디폴트는 아니어서 크로스-컴파일을 어렵게 한다. | |
| 342 | + | - 컴파일러는 비-아스키 문자를 가진 모든 문자열 상수를 widesring 상수로 변환한다. 이는 자동적을 ansistring으로 변환된다(컴파일시 혹은 실행시), 하지만 이는 두 문자를 합치거나 단일 문자열 상수에 ordinal 값이 있다면 경고를 보여 준다: | |
| 343 | + | ||
| 344 | + | 예를 들면: | |
| 345 | + | ||
| 346 | + | ``` pascal | |
| 347 | + | program project1; | |
| 348 | + | {$codepage utf8} | |
| 349 | + | {$mode objfpc}{$H+} | |
| 350 | + | {$ifdef unix} | |
| 351 | + | uses cwstring; | |
| 352 | + | {$endif} | |
| 353 | + | var | |
| 354 | + | a,b,c: string; | |
| 355 | + | begin | |
| 356 | + | a:='ä'; | |
| 357 | + | b:='='#$C3#$A4; // #$C3#$A4 is UTF-8 for ä | |
| 358 | + | c:='ä='#$C3#$A4; | |
| 359 | + | writeln(a,b); // writes ä=ä | |
| 360 | + | writeln(c); // writes ä=ä | |
| 361 | + | end. | |
| 362 | + | ``` | |
| 363 | + | ||
| 364 | + | 컴파일하고 실행하면, 이렇게 쓸 것이다: | |
| 365 | + | ||
| 366 | + | ä=ä | |
| 367 | + | ä=ä | |
| 368 | + | ||
| 369 | + | 이유는 *ä* 이 나타나 위에 언급한 대로 'c'에 해당하는 상수 문자열의 나머지 부분이 widestring으로 분류 되기 때문이다. 결과적으로 \#\$C3 와 \#\$A4 는 ansichar 대신 widechar(#\$C3) 와 widechar(#\$A4) 로 해석된다. | |
| 370 | + | ||
| 371 | + | # 더 보기 | |
| 372 | + | ||
| 373 | + | - [[Character and string types|문자와 문자열 타입]] | |
| 374 | + | - [[UTF-8]] - UTF-8 문자열 설명 | |
| 375 | + | - [[FPC Unicode support|FPC 유니코드 지원]] | |
| 376 | + | - [[for-in loop|for-in_loop#Traversing_UTF-8_strings]] - UTF8문자열을 통달하는 방법을 보여주는 코드 | |
| 377 | + | - [[unicode use cases|유니코드 사용 예]] | |
| 378 | + | ||
| 379 | + | --- | |
| 380 | + | *From the Free Pascal wiki, page "LCL Unicode Support/ko", as it stood on 2020-02-19 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
