LazarusCompleteGuide:1.7
유니코드
오랜 시간 동안 VCL은 AnsiString 만을 지원하였으며, 이러한 지원은 델파이 2009 이전까지 변하지 않았다. 또한 표시되었던 모든 캡션은 현재 코드 페이지에 발견되는 문자로부터 구성해야 했다. 0.9.26 이상 버전부터 LCL는 모든 플랫폼에서 UTF-8을 기반으로 한다. 즉, 비영어 문자를 포함한 모든 문자를 이용할 수 있음을 의미한다. UTF-8은 0-127까지 범위의 ASCII 호환이 되는 8자리 유니코드 부호화로, 특별히 기존 코드를 유니코드로 복사하는 과정을 단순화시키기 위해 설계되었다. 월드 와이드 웹(World Wide Web)은 부분적으로 UTF-8을 기반으로 하며, Linux와 Mac OS X의 그래픽 사용자 인터페이스들도 마찬가지다. BSD는 UTF-8을 마지못해 매우 기본적으로만 지원한다. 라자루스로 이전된 델파이 프로그램들이나 오래된 라자루스 프로그램들의 경우 다음이 적용된다:
- 문자열은 8비트 문자열로 유지된다.
- 영문 상수와 문자열은 변경하지 않고 복사할 수 있다.
- 영어가 아닌 문자 혹은 ASCII 가 아닌 문자를 포함하는 상수와 문자열은 검사를 받아야 한다. 대부분의 경우, 소스 파일의 인코딩을 변경하는 것으로 충분하다. 예를 들어, 라자루스에서 소스 파일은 소스 에디터의 팝업 메뉴에서 File Settings... ⇒ Encoding 을 선택해 UTF-8로 변환이 가능하다. 전체 프로젝트나 패키지는 Tools ⇒ Convert encoding of projects/packages... 를 선택하여 변환할 수 있다.
- 파일 조작: RTL은 여전히 시스템 인코딩을 사용하므로, 여기에 사용되는 문자열은 변환되어야 한다. RTL 함수 AnsiToUTF8와 UTF8ToAnsi 가 이러한 목적으로 제공된다. 또한 LCL은 LCLProc 과 FileUtil 유닛에 UTF... 함수 집합을 제공한다. 가장 중요한 함수는 다음과 같다:
function UTF8ToSys(const s: String): String; // UTF8ToAnsi와 같지만
// LCL에 최적화됨.
function SysToUTF8(const s: String): String; // UTF8ToAnsi와 같지만
// LCL에 최적화됨
function UTF8ToConsole(const s: String): String; // WriteLn에 대한 UTF8문자열을
// 인코딩함
아래 함수와 프로시저는 프리 파스칼 런타임 라이브러리로의 호출에 상응하는 UTF-8 이다.
function FileExistsUTF8(const Filename: String): Boolean;
function FileAgeUTF8(const FileName: String): Longint;
function DirectoryExistsUTF8(const Directory: String): Boolean;
function ExpandFileNameUTF8(const FileName:String): String;
function ExpandUNCFileNameUTF8(const FileName: String): String;
function ExtractShortPathNameUTF8(const FileName : String): String;
function FindFirstUTF8(const Path: String; Attr: Longint; out Rslt: TSearchRec): Longint;
function FindNextUTF8(var Rslt: TSearchRec): LongInt;
procedure FindCloseUTF8(var F: TSearchrec);
function FileSetDateUTF8(const FileName: String; Age: Longint): LongInt;
function FileGetAttrUTF8(const FileName: String): LongInt;
function FileSetAttrUTF8(const Filename: String; Attr: Longint): LongInt;
function DeleteFileUTF8(const FileName: String): Boolean;
function RenameFileUTF8(const OldName, NewName: String): Boolean;
function FileSearchUTF8(const Name, DirList : String): String;
function FileIsReadOnlyUTF8(const FileName: String): Boolean;
function GetCurrentDirUTF8: String;
function SetCurrentDirUTF8(const NewDir: String): Boolean;
function CreateDirUTF8(const NewDir: String): Boolean;
function RemoveDirUTF8(const Dir: String): Boolean;
function ForceDirectoriesUTF8(const Dir: String): Boolean;
function ParamStrUTF8(Param: Integer): String;
function GetEnvironmentStringUTF8(Index: Integer) String;
function GetEnvironmentVariableUTF8(const EnvVar: String): String;
function GetAppConfigDirUTF8(Global: Boolean): String;
function SysErrorMessageUTF8(ErrorCode: Integer): String;
많은 텍스트 파일들이 고유의 문자 인코딩에 관한 정보는 전혀 포함하지 않으며 주로 운영체제의 인코딩을 사용한다. 윈도우에서는 최근 윈도우 코드 페이지가 이에 해당한다 (예를 들어, 윈도우의 독일어 버전에서는 코드 페이지 1250, 러시아어는 코드 페이지 1251). UTF-8은 Linux와 MacOS X의 그래픽 사용자 인터페이스의 표준으로, 서유럽에서는 ISO 8859-15가 사용되고 8비트 ISO 인코딩이 일반적으로 BSD에서 선호되긴 하지만 매우 한정된 범위에서만 사용된다.
LCL 유닛인 Lconvencoding은 텍스트 파일의 플랫폼 독립적인 읽기 및 쓰기를 가능하게 한다. 이는 텍스트 파일의 시스템 인코딩을 결정하고 변환하는 함수들을 제공한다. 텍스트 파일이 열리면 인코딩이 먼저 결정되어야 한다. GuessEncoding 함수는 문자열의 인코딩을 짐작하고자 시도한다. 먼저 UTF 바이트 순서 표시(BOM)와 같은 일반적 표시를 검색한다. 표시를 찾지 못하면 UTF-8에 맞지 않는 텍스트를 검사한다. UTF-8은 ASCII가 아닌 문자에 대해 특수 비트 패턴과 함께 멀티바이트(multibyte) 코드를 사용한다. 해당 비트 패턴들은 윈도우 코드 페이지로 인코딩된 텍스트가 패턴을 위반할 가능성이 높기 때문에 설계되었다. 따라서 UTF-8을 인식하기가 쉽다. 텍스트가 UTF-8로 인코딩되지 않은 경우 GuessEncoding은 시스템 인코딩을 반환한다.
ConvertEncoding 함수는 문자열을 변환하는 데 사용할 수 있다. 내부에서 ConvertEncoding은 윈도우 1250 코드 페이지로 인코딩된 문자열을 UTF-8로 인코딩된 문자열로 변환하는 CP1250ToUTF8 등등 다양한 변환 함수들을 호출한다. 아래 함수는 텍스트 파일을 읽어 텍스트를 UTF-8로 변환한 후 텍스트와 고유의 인코딩(original encoding)을 리턴한다:
function LoadTextFile(const FileName: String; out EncodingFile: String): String;
var fs: TFileStream;
begin
EncodingFile := EncodingUTF8;
fs := TFileStream.Create(FileName, fmOpenRead);
try
SetLength(Result, fs.Size);
if Result <> '' then fs.Read(Result[1], Length(Result));
EncodingFile := GuessEncoding(Result);
Result := ConvertEncoding(Result, EncodingFile, EncodingUTF8);
finally
fs.Free;
end;
텍스트는 TMemo 컴포넌트 등 어디서든 표시할 수 있다:
Memo1.Lines.Text := LoadTextFile('test.txt', CodingFile);
다음 프로시저는 결과를 저장한다:
procedure SaveTextFile(const FileName, Contents, EncodingFile: String);
var fs: TFileStream; s : String;
begin
fs := TFileStream.Create(FileName, fmCreate);
try
s := ConvertEncoding(Contents, EncodingUTF8, EncodingFile);
if s <> '' then fs.Write(s[1], Length(s));
finally
fs.Free;
end;
end;
아래 문장은 고유의 인코딩이 있는 TMemo 컴포넌트의 내용을 저장한다:
SaveTextFile('test.txt', Memo1.Lines.Text, CodingFile);
UTF-8은 모든 윈도우 코드 페이지를 포함해 전체 유니코드 문자 집합을 포함하지만 그러한기타 문자들이 UTF-8을 모두 포함하지는 않는다는 사실을 명심하라. 예를 들어, CP1250는 ASCII 문자와 독일어 움라우트 문자 등 다수의 유럽 언어 문자만 포함한다.
즉, UTF-8을 CP1250로 변환 시 CP1250에 표시되지 않은 문자는 (예: 일본어 문자) 조용히 제거되버린 것이다.