Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2021年01月29日] [更新 2021年03月14日] Delphi 一般・その他
   
テキストの保存とコードページ指定と文字化け
動作確認等 Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
[整理番号 - 0830]







テキスト ( 文字列 ) の保存とコードページ指定と文字化け


Delphi 2009 で Delphi がユニコード化され,10 年以上が経過しました.
Delphi 2007 以前の,いわゆる ANSI 版の Delphi では,文字 はバイト単位の処理で,1 バイト文字,2 バイト文字というのがありました.Delphi 2009 以降の Unicode の文字は,コードポイントの 2 バイトであるエレメント単位の処理になりました.そのことに関するトラブルもありますが,ここではテキストの保存の基本的な処理だけに的を絞って,その動作を確認してみました.






01_文字のバイナリデータ ( コードポイント )


文字のバイナリデータの値を調べてみます.これは,その文字のコード,コードポイントのことです.文字のバイナリ値は Ord 関数で調べることができます.
下図は文字「唖」を調べた結果です.16 進数で 5516 となっています.Delphi 2009 以降の String 型はユニコードの UTF-16 です.
この表には,Shift_JIS には存在しない文字が多くあります.


16 進数 0 1 2 3 4 5 6 7 8 9 A B C D E F
U+5510
U+5520
U+5530


以下の参考リンクのユニコードコンソーシアムのサイトでも,文字のコードポイントを調べることができます.「唖」は 16 進数で 5516 になっています.Unicode の漢字は,情報処理推進機構のサイトでも検索することができます.



最初のリンクでは,[Lookup]ボタンの右側の入力欄に文字,またはコードポイントのの値を入力して [Lookup] ボタンをクリックします.
2 番目のリンクでの検索では,「対応する UCS」が UTF-16 のコードポイントです.UTF-16 のコードポイントは U+XXX の形式で入力します.
3 番目のリンクでは,右上の入力欄に,漢字またはコードポイントの値を入力します.



図1
文字「唖」のコードポイントは 16 進数で 5516

リスト1
//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Text := '唖娃';
end;

//=============================================================================
//  文字列の最初の文字のコードポイントを 16 進数表示
//  これはその文字のバイナリデータの値
//  結果 : 唖のコードポイントは $5516
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText : string;
begin
  Memo1.Lines.Add(IntToHex(Ord(Memo1.Lines.Text[1]), 4));

  LText := '唖娃';
  Memo1.Lines.Add(IntToHex(Ord(LText[1]), 4));
end;


TMemo のテキストを TMemo.SaveToStream メソッドでメモリストリームに保存します.そのメモリのデータを String 型の変数に読み込んで,バイナリデータを調べてみます.結果は 16 進数で 88A0 となっています.文字「唖」の Unicode のコードポイントは 5516 ですから,全く違う値です.
下の表は Shift_JIS のコードポイントです.88A0 の箇所を見ると,この「唖」という文字になっています.つまり,88A0 という値は,Shift_JIS の文字コードです.


16 進数 0 1 2 3 4 5 6 7 8 9 A B C D E F
88A0
88B0
88C0


一般的に,同じ文字であっても,文字符号化方式,つまり,コードページが異なれば,コートポイントの値も異なります.



図2
メモリストリームに保存した「唖」の文字コート
  • Shift_JIS のコードポイントになっている

リスト2
//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Text := '唖娃';
end;

//=============================================================================
//  TMemo の文字列をメモリストリームに書き込む
//  書き込んだ文字列を読み出してコードポイントを 16 進数で表示
//
//  SaveToFile, SaveTpStream で保存するとバイトオーダが逆順になる
//  それを Swap 関数で上位バイトと下位バイトを入れ換えてから処理
//  結果 : 唖のコードポイントは $88A0
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LStream  : TMemoryStream;
  LText    : string;
  LAnsiStr : AnsiString;
begin
  LStream := TMemoryStream.Create;
  try
    Memo1.Lines.SaveToStream(LStream);

    SetLength(LText, LStream.Size);
    LStream.Position := 0;
    LStream.Read(LText[1], LStream.Size);
    Memo1.Lines.Add(IntToHex(Swap(Ord(LText[1])), 4));
  finally
    FreeAndNil(LStream);
  end;

  // AnsiString 型の変数に代入して調べてみる
  LAnsiStr := '唖娃';
  Memo1.Lines.Add(IntToHex(Ord(LAnsiStr[1]), 2) + IntToHex(Ord(LAnsiStr[2]), 2));
end;




02_テキスト保存時のデフォルトは Shift_JIS


TMemo や TStringList 等で,SaveToStream あるいは SaveToFile メソッドでテキストを保存すると,デフォルトで Shift_JIS で保存するようになっています.その確認用のサンプルです.

TMemo に表示しているテキストを SaveToFile で保存して,LoadFromFile で読み込む単純なサンプルです.Shift_JIS にはない文字,ユニコードな文字も含めてテストしています.下図の結果のように,ユニコードな文字は正常に表示できません.



図3
起動時の画面
  • TMemo にテキストを表示
  • これを保存して読み込む
図4
保存して読み込んだ結果
  • Shift_JIS で保存したテキストを Shift_JIS として読み込んで表示したことになる
  • Shift_JIS で保存されているので,ユニコードな文字でなければ正常に表示される

リスト3
var
  FFilePath : string;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;

  //文字列をセット
  Memo1.Lines.Add(#$4F60#$597D + ' !!');
  Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
  Memo1.Lines.Add('テキストを保存');

  FFilePath := ExpandFileName('.\000.txt');
end;

//=============================================================================
//  TMemo のテキストを SaveToFile メソッドでファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.SaveToFile(FFilePath);
end;

//=============================================================================
//  テキストを保存したファイルを読み込んで TMemo で表示
//  ユニコードな文字は正常に表示できない
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  if not FileExists(FFilePath) then Exit;

  Memo1.Lines.LoadFromFile(FFilePath);
end;


以下は TStringList の場合です.結果は上の TMemo の場合と全く同じです.
この仕様により,ユニコードな文字を含まないテキストであれば,Delphi 2009 以降で作成したプログラムで保存したテキストファイルを,Delphi 2007 以前で作成したプログラムでも読み込んで正常に表示できます.逆に,Delphi 2007 以前のプログラムで保存したテキストファイルを,Delphi 2009 以降で作成したプログラムで読み込んで表示することが可能です.

Windows は,Windows Vista で全面的に Unicode 化されましたが,メモ帳のデフォルトの文字コードは ANSI (日本語版の Windows では Shift_JIS) です.メモ帳でテキストを入力して保存する際,文字コードを指定しなければ ANSI での保存となります.



図5
TStringList の場合
  • Shift_JIS で保存したテキストを Shift_JIS として読み込んで表示したことになる
  • ユニコードな文字は保存前と同じ文字にならない

リスト4
var
  FFilePath : string;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  FFilePath := ExpandFileName('.\000.txt');
end;

//=============================================================================
//  TStringList に文字列をセットしてファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LStrList : TStringList;
begin
  LStrList := TStringList.Create;
  try
    LStrList.Add(#$4F60#$597D + ' !!');
    LStrList.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
    LStrList.Add('テキストを保存');

    LStrList.SaveToFile(FFilePath);
  finally
    FreeAndNil(LStrList);
  end;
end;

//=============================================================================
//  保存したテキストを TStringList に読み込んで TMemo に表示
//  ユニコードな文字は正常に表示できない
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LStrList : TStringList;
begin
  if not FileExists(FFilePath) then Exit;

  LStrList := TStringList.Create;
  try
    LStrList.LoadFromFile(FFilePath);
    Memo1.Lines.Text := LStrList.Text;
  finally
    FreeAndNil(LStrList);
  end;
end;


上のサンプルでは,ユニコードな文字をコードポイントで設定しています.Delphi 2009 以降の IDE のコードエディタの [ファイルフォーマット] は UTF-8 にできます.そうすれば,下図のような,ユニコードな文字の編集結果も保存できます.
[ファイルフォーマット] の設定は,コードエディタのポップアップメニューにあります.



図6
IDE のコードエディタ
  • ユニコードな文字も扱える

[備考]
Windows 10 のメモ帳は,2019年5月の Windows 10 の Update で,UTF-8 が既定のコードページに変更されています.




03_テキストの保存と読み込み時のコードページ指定と BOM


Unicode (UTF-16) な文字も保存するには,SaveToStrem メソッドや SaveToFile メソッドの第 2 引数でコードページを指定します.コードページの指定には TEncoding が使用できます.コードページの指定を省略すると,上のサンプルで確認したように,Shift_JIS となります.
ファイルからテキストを LoadFromFile メソッドで読み込む時は,そのファイル内のテキストのコードページを指定して読み込みます.この時も TEncoding が使用できます.

Delphi 2009 以降では,以下の 2 番目のリンクの記事のように,文字列のコードページ変換も簡単に処理できるようになっています.



  TEncoding.Unicode           // Unicode (UTF-16)
  TEncoding.UTF8              // UTF-8
  TEncoding.ANSI              // ANSI (日本語環境では Shift_JIS)
  TEncoding.GetEncoding(932)  // Shift_JIS
  TEncoding.Default           // 日本語環境ではコードページ 932 の Shift_JIS


以下は TMemo のテキストの保存と読み込みの例です.
UTF-8 または Unicode を指定してテキストを保存すると,先頭に BOM と呼ばれる識別用のコードが追加されます.この BOM があると,テキストの読出しの際,コードページを指定しなくても,自動的にコードページの判定が行われます.そのテストもしています.

BOM 付きのテキストファイルを,TMemo.LoadFromSteam, TMemo.LoadFromFile で読み込んでも,BOM 自身のデータは TMemo のデータとしては読み込まれません.BOM は,UTF-8 または Unicode の判定に使用されるだけです.



図7
実行開始時の画面
  • ユニコードな文字を含む,このテキストを保存して読み込む
図8
保存したテキストを読み込んだ結果
  • Unicode で保存したので,ユニコードな文字も正常に表示されている
  • Button2 クリックのコードでも結果は同じ

リスト5
var
  FFilePath : string;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;

  //文字列をセット
  Memo1.Lines.Add(#$4F60#$597D + ' !!');
  Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
  Memo1.Lines.Add('テキストを保存');

  FFilePath := ExpandFileName('.\000.txt');
end;

//=============================================================================
//  TMemo のテキストをファイルに保存
//  保存時に TEncoding を使用してエンコード指定
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.SaveToFile(FFilePath, TEncoding.Unicode);
end;

//=============================================================================
//  保存したテキストファイルを TMemo に読み込む
//  読み込み時に TEncoding を使用してエンコード指定
//
//  保存しているテキストのコートページを明らかにする
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  if not FileExists(FFilePath) then Exit;

  Memo1.Lines.LoadFromFile(FFilePath, TEncoding.Unicode);
end;

//=============================================================================
//  保存したテキストファイルを TMemo に読み込む
//  読み込み時に TEncoding を使用しない場合
//
//  UTF-8 または Unicode (UTF-16) を指定して保存すると先頭に識別子 (BOM) が付く
//  BOM があると,読み込むテキストのコートページを自動判定してくれる
//  一般的にはエンコードを指定した方が良い
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  if not FileExists(FFilePath) then Exit;

  Memo1.Lines.LoadFromFile(FFilePath);
end;


意図的に BOM なしで保存することもできます.TMemo.Lines や TStringList の TStrings の派生クラスには WriteBOM プロパティがあります.そのプロパティの値を False にします.



procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.WriteBOM := False;
  Memo1.Lines.SaveToFile(FFilePath, TEncoding.Unicode);
end;


BOM なしのテキストを読み込む例です.
文字列のデータを TMemoryStream に書き込みます.TMemoryStream.SaveToFile でそのメモリストリームのデータをファイルに保存します.TMemoryStream の SaveToFile メソッドは,バイトデータをそのまま保存しますから,識別子としての BOM は追加されません.
BOM がない場合,Unicode で保存していても,コードページを指定して読み込まないと,保存されているデータを Shift_JIS のコードポイントのデータとして読み込みます.その結果,保存前と同じ文字にはなりません.



図9
テキスト読み込み時にコードページを指定しない場合
図10
テキスト読み込み時にコードページを指定した場合

リスト6
var
  FFilePath : string;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;

  //文字列をセット
  Memo1.Lines.Add(#$4F60#$597D + ' !!');
  Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
  Memo1.Lines.Add('テキストを保存');

  FFilePath := ExpandFileName('.\000.txt');
end;

//=============================================================================
//  TMemo のテキストを String 型の変数に代入
//  そのテキストのバイナリデータをメモリストリームに書き込んでファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText   : string;
  LStream : TMemoryStream;
begin
  LText := Memo1.Lines.Text;

  LStream := TMemoryStream.Create;
  try
    LStream.Write(LText[1], Length(LText) * SizeOf(Char));
    LStream.SaveToFile(FFilePath);
  finally
    FreeAndNil(LStream);
  end;
end;

//=============================================================================
//  保存したテキストファイルを TMemo に読み込む
//  読み込み時のエンコード指定なし
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile(FFilePath);
end;

//=============================================================================
//  保存したテキストファイルを TMemo に読み込む
//  読み込み時のエンコード指定あり
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile(FFilePath, TEncoding.Unicode);
end;


次のように,TMemoryStream を保存する時に,意図的に BOM を追加することもできます.


procedure TForm1.Button1Click(Sender: TObject);
var
  LText   : string;
  LStream : TMemoryStream;
  LBOM    : TBytes;
begin
  LText := Memo1.Lines.Text;

  LStream := TMemoryStream.Create;
  try
    LBOM := TEncoding.Unicode.GetPreamble;
    LStream.Write(LBOM[0], Length(LBOM));

    LStream.Write(LText[1], Length(LText) * SizeOf(Char));
    LStream.SaveToFile(FFilePath);
  finally
    FreeAndNil(LStream);
  end;
end;


BOM のバイナリ値は,下図のようになっています.



図11
BOM のバイナリ値
  • 最初の値は Unicode (UTF-16) の BOM
  • 次の値は UtF-8 の BOM

リスト7
procedure TForm1.Button1Click(Sender: TObject);
var
  LBOM  : TBytes;
  LText : string;
  LIdx  : Integer;
begin
  // Unicode (UTF-16) の BOM データ
  LBOM := TEncoding.Unicode.GetPreamble;
  LText := '';
  for LIdx := 0 to Length(LBOM) -1 do begin
    LText := LText + IntToHex(LBOM[LIdx], 2);
  end;
  Memo1.Lines.Add('$' + LText);

  // UTF-8 の BOM データ
  LBOM := TEncoding.UTF8.GetPreamble;
  LText := '';
  for LIdx := 0 to Length(LBOM) -1 do begin
    LText := LText + IntToHex(LBOM[LIdx], 2);
  end;
  Memo1.Lines.Add('$' + LText);
end;


[備考 1]
BOM (byte order mark - バイトオーダマーク) は,正確にはバイトオーダの識別用です.

[備考 2]
Windows のメモ帳で BOM なしの Unicode のテキストを読み込む時は,Unicode を指定して読み込まないと文字化けします.BOM 付きの Unicode のテキストであれば,自動的に判定して正常に表示してくれます.




04_コードページの違いが原因で発生する文字化け


コードページの指定が適切でないと文字化けが発生することを再確認してみます.
下図は,Shift_JIS で保存したテキストを TMemo に読み込んで表示する際,Unicode を指定しために文字化けした結果です.
このように,意図しない文字が表示される状態を一般的に「文字化け」と言っています.

カタカナの「ユ」 は,Shift_JIS では $8386 ですが,Unicode としてメモリストリームやファイルから読み込む時は,バイトオーダが逆順に読み込まれます.その結果,コードポイント $8683 の文字として表示されます.



図12
テストに使用した文字列
図13
一般的に言われる「文字化け」
  • Shift_JIS のテキストを Unicode として読み込んで表示した結果
  • 意図しない文字が表示される

下図は,UTF-8 で保存したテキストを TMemo に読み込んで表示する際,Unicode を指定しために文字化けした結果です.
このサンプルは,文字化けを発生させる極端な例ですが,テキストとして文字列を扱う場合,コードページに注意する必要があります.データベースの文字列項目のデータを処理する場合もコートページの確認が必要なことがあります.文字化けは,文字列の処理過程でも発生する可能性があります.



図14
一般的に言われる「文字化け」
  • UTF-8 のテキストを Unicode として読み込んで表示した結果
  • 意図しない文字が表示される

リスト8
var
  FFilePath : string;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;

  // 文字列をセット
  Memo1.Lines.Add('ユニコードな文字なし');
  Memo1.Lines.Add('テキストを保存');

  FFilePath := ExpandFileName('.\000.txt');
end;

//=============================================================================
//  TMemo のテキストを Shift_JIS で保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.SaveToFile(FFilePath);
end;

//=============================================================================
//  保存したテキストファイルを TMemo に読み込む
//  読み込み時に Unicode を指定
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile(FFilePath, TEncoding.Unicode);
end;


上のサンプルは,Unicode への変換で文字化けする例でした.以下のサンプルは,UTF-8 への変換で文字化けする例です.
Delphi ではこのサンプルの最後のコードのように,コードページの文字列型の変数に代入するだけでコードページの変換ができてしまいます.そのため,UTF-8 への変換で文字化けさせるのは難しいのですが,強引に文字化けするようにしてみました.
このサンプルの文字列は,UTF-8 では 1 文字に 3 バイト使用するので合計 9 バイト使用します.

Unicode (UTF-16) では最低でも 1 文字で 2 バイト使用します.その結果,Unicode として文字列のデータを読み込む時は,文字化けとして多くの場合,漢字が表示されます.
Shift_JIS や UTF-8 には 1 バイトの文字があります.それらの多くは ASCII 文字としてのバイナリデータです.その結果,文字化けとして半角の英数字が多く表示されます.読み出すバイト値が 0 の場合 は Null 文字ですから,それ以降のバイナリデータは文字として表示しないことになります.前項のサンプルにその例があります.


  // Null 文字以降の文字は表示しない
  ShowMessage('ABC' + #$0 + '日本語');


図15
UTF-8 への変換で文字化けする例

リスト9
//=============================================================================
//  UTF-8 への変換で無理やり文字化けを発生させる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LStream  : TMemoryStream;
  LUniStr  : string;
  LUtf8Str : UTF8String;
begin
  LUniStr := '日本語';

  LStream := TMemoryStream.Create;
  try
    // メモリストリームに String 型の文字列のデータを書き込む
    // 書き込むバイト数は 6 バイト
    LStream.Write(LUniStr[1], Length(LUniStr) * SizeOf(Char));

    SetLength(LUtf8Str, 9);
    // メモリストリームのデータを UTF-8 型の文字列に読み込む
    LStream.Position := 0;
    LStream.Read(LUtf8Str[1], LStream.Size);
    Memo1.Lines.Add(LUtf8Str);
  finally
    FreeAndNil(LStream);
  end;

  SetLength(LUtf8Str, 0);
  // 通常は以下で十分
  LUtf8Str := LUniStr;
  Memo1.Lines.Add(LUtf8Str);
end;


コードポイントとしての文字の割り当てがない場合,Unicode では文字「・」( U+30FB ) を使用します.これをデフォルトの文字,あるいは代替文字 (REPLACEMENT CHARACTER) と言います.Shift_JIS の代替文字は「?」( $3F ) です.上の方のサンプルの実行結果の図で表示されていた ? は,この代替文字です.UTF-8 の代替文字は,上のサンプルのように「�」( $EFBFBD = U+FFFD ) です.



図16
代替文字

リスト10
//=============================================================================
//  代替え文字
//  デフォルトの文字とも言う
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LUniStr  : string;
  LAnsiStr : AnsiString;
  LUtf8Str : UTF8String;
  LCpInfo  : TCPInfoEx;
begin
  LUniStr := #$30FB;

  SetLength(LAnsiStr, 1);
  LAnsiStr[1] := #$3F;

  SetLength(LUtf8Str, 3);
  LUtf8Str[1] := #$EF;
  LUtf8Str[2] := #$BF;
  LUtf8Str[3] := #$BD;

  Memo1.Lines.Add(LUniStr + ' ' + LAnsiStr + ' ' + LUtf8Str);

  // GetCPInfoEx 関数で UTF-8 の代替文字を取得
  GetCPInfoEx(65001, CP_ACP, LCpInfo);
  Memo1.Lines.Add(LCpInfo.UnicodeDefaultChar);
end;


[備考]
文字化けは,表示したり印刷しないと確認できません.文字化けしてしまう,という質問には,どの様な処理でどこに表示したという記述がない質問があります.その場合,当然ながら,原因の特定は困難になります.




05_文字符号化方式とコードページとコードポイント


コンピュータでは,文字そのものを記憶したり保存すことはできません.文字に数値 (番号) を割り当てて,その数値を記憶したり保存します.文字に番号を割り当てて,各々の文字を区別することを符号化と言います.
文字の符号化は,コンピュータメーカがそれぞれ独自に文字符号化方式を作成していました.その結果,いくつもの文字符号化方式が存在することになりました.日本では,1978年に JIS が文字符号化集合としての規格を制定しています.

最初のサンプルで示したように,同じ文字でも,文字符号化方式によって,文字のコード,つまり文字に割り当てられた値が違います.その値を,どの文字符号化方式で処理するかによって文字が違ってきます.

符号化した文字集合をコードページと言います.各々の文字符号をコードポイントと言いますが,符号点,符号化点,文字コードと言うこともあります.JIS の符号化のコードは,JIS コード,あるいは,漢字コードと言うこともあり,実に様々です.文字コードと言う用語は,文字符号化方式の意味にもコードポイントの意味でも使われています.文字符号化方式は,文字符号化形式と言うこともあります.

Windows では,マイクロソフトが策定した文字符号化方式を,ANSI (米国国家規格協会) が制定した方式が使用されてきました.ANSI の文字符号化方式は,国と地域によってコードページが異なります.日本語版の Windows のコードページは 932 です.Delphi 2007 以前の String 型と,Delphi 2009 以降の AnsiString 型は,この文字符号化方式を使用します.このことから,Delphi 2007 以前を ANSI 版の Delphi と言っています.

コードページ 932 の文字符号化方式は,Shift_JIS を拡張した内容になっていますが,Shift_JIS という名称が一般的に使われています.



言語に依存せず,プログラムにも依存せず,プラットフォームにも依存しない,全ての文字に固有の番号を割り当てることを目的でユニコードコンソーシアム (The Unicode Consortium) が 1990年12月に設立されました.ユニコードコンソーシアムが策定・改訂した内容は,ISO(国際標準化機構),IEC(国際電気標準会議)が制定しています.ユニコードコンソーシアムが策定した文字符号化方式をユニコードと呼んでいます.

1993年に UCS-2 (Universal multi-octet Character Set 2) が制定されました.UCS-2 には,世界で一般的に使用される文字,記号のほとんどが収録されています.その後, UCS-2 を改定して,より多くの文字を扱える UTF-8 と UTF-16 が制定されました.

UTF-8 は 8 ビット (1 バイト) を単位とした可変長バイトの符号化方式です.UTF-16 は,UCS-2 で定義された文字は 16 ビット (2 バイト) で,それ以外は可変長バイトの符号化方式となっています.その他に 32 ビット (4 バイト) の固定長の UTF-32 があります.これらは全て Unicode ですが,単に Unicode と言う時は UTF-16 のことを意味します.Delphi 2009 以降の String 型,PChar 型,Char 型は UTF-16 を使用します.
UTF-8 のコードページは 65001 です.UTF-16 のコードページは 1200 です.



Unicode に登録されている文字は,Unicodeコンソーシアムが公開しています.
上のリンクの最初の PDF は,Unicode の文字のリストとなっています.2 番目は画数,部首順のリストです.3 番目の PDF は異体字のリストです.



[備考 1]
コードページという用語は,ISO / IEC 等の規格文書では使われていません.コードページという用語は,システムベンダが文字の符号化方式を区別するために使用している用語です.
コードページ (code page) は,プリフィックスとして CP を付けて表記することがあります.
Shift_JIS, UTF-8, UTF^16, Unicode 等は,文字符号化方式の名称 (名前) ですが.コードページの名称とも言えます.

[備考 2]
Shift_JIS という用語は,IANA (Internet Assigned Numbers Authority - インターネット番号割当機関) が定義して使用されてきた用語です.JIS (日本産業規格) の規格名にも規格文書にも使用されていませんでした.
JIS X 0208 が,JIS における Shift_JIS 相当の文字符号化方式の規格です.名称は「7 ビット及び 8 ビットの 2 バイト情報交換用符号化漢字集合」ですが,2000年発行の,JIS X 0208 規格文書の付属書 Shift_JISX0213 で,Shift_JIS の名称が定義されています.

[備考 3]
現在実際に使用されている文字の他に,考古学的な意味を持つ文字も含めると,文字の数は膨大です.特に漢字の数は 18 万を越えます.2022年9月13日リリースの Unicode 15.0.0 ば,絵文字なども含めて文字数は 149,186 となっています.それらの全ての文字が Windows に標準実装されているフォントで使用できるわけではありません.