|
Delphi Programming / Object Pascal
[掲載 2008年04月03日] [更新 2014年04月12日] Delphi サンプルプログラム集 |
886_MLang.dll の関数を使用した文字コードの変換 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE Pro |
|
886_ChangeCodePage.zip [3,396 KB] 2012年04月12日版 (EXE 同梱) |
- 2014年04月12日
- Windows 7 U64(SP1) + Delphi XE Pro で動作確認
- 言語名の取得のサンプルを Vista 以降に対応
- URL の文字列のデコード,エンコードのサンプルを,HTTPApp 内の関数を使用するコードから,TIdURL を使用するコードに変更
|
テキストファイルの文字のコードページの変換のサンプルです.
主に IE (Web ブラウザ Internet Explorer) で使用されている MLang.dll の機能を使用した方法をテストしています.
本ページで使用している MultiLanguage_TLB.pas は [IDL コンパイラを使用したタイプライブラリの作成と取り込み] 記事の説明に従って作成したものです.このユニットを,プロジェクトに追加して使用しています. |
Delphi 2009 以降では,テキストファイルの保存の時に TEncoding を使用して,コードページを指定することができます.また,以下のリンクの記事のように,指定コードページ (文字コード) の文字列型を定義して文字列を処理てきるようになり,文字コードの変換が簡単にできます.
本ページのようなサンプルコードを利用する必要性はほとんどないでしょう. |
01_文字コード ( コードページ ) の言語名一覧 |
文字コードに対応する言語名を取得するサンプルです.
言語名は,下図のように,レジストリの以下の場所にあります.その中の Description の値が言語名です. |
HKEY_CLASSES_ROOT\MIME\Database\Codepage
- 図1
- Windows XP の文字コードとその言語名
|
|
Windows Vista 以降では,下図のように,この Description キーに言語名はありません. |
- 図2
- Windows 7 の文字コードとその言語名.実際には言語名はない
|
|
そこで,本サンプルでは,Vista 以降とそれよりも前とで処理を分岐しています. Windows XP 以前ではレジストリの値から言語名を取得します.一方,Vista 以降では IMultiLanguage インターフェイス の GetCodePageInfo 関数で取得するようにしています.
下図はその実行結果です.システムで使用可能な言語名をリストします. |
|
図3
設計時画面
|
|
図4
実行結果
- 左が文字コードページの値
- 右は,それに対応する言語名
|
リスト1
システムで使用可能な文字コードと言語名をリストする |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
CodeList : TStringList;
DistributeList : TStringList;
procedure GetCodeAndDistributeList(slCode, slDistribute : TStringList);
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses Registry, MultiLanguage_TLB, ComObj;
{$R *.dfm}
//=============================================================================
// システムで使用可能な文字コードページ(文字セット)をリスト表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
StrText : String;
i : Integer;
begin
CodeList := TStringList.Create;
DistributeList := TStringList.Create;
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
try
GetCodeAndDistributeList(CodeList, DistributeList);
for i := 0 to CodeList.Count - 1 do begin
StrText := Format('%5s', [CodeList[i]]);
Memo1.Lines.Add(StrText + ' ' + DistributeList[i]);
Application.ProcessMessages;
end;
finally
Memo1.Lines.EndUpdate;
FreeAndNil(CodeList);
FreeAndNil(DistributeList);
end;
end;
//=============================================================================
// 文字コードと文字コード名のリストを作成
// slCodeList : 文字コードの格納リスト
// slDistribute : 文字コード名の格納リスト
//=============================================================================
procedure TForm1.GetCodeAndDistributeList(slCode, slDistribute : TStringList);
var
Registry : TRegistry;
RegKey : String;
slGCodePage : TStringList;
MLang : IMultiLanguage;
MIMECPInfo : TMIMECPINFO;
i : Integer;
strDescription : String;
begin
slGCodePage := TStringList.Create;
slCode.Clear;
slDistribute.Clear;
//レジストリから文字コードの情報を取得してリストに格納
Registry := TRegistry.Create(KEY_READ);
try
Registry.RootKey := HKEY_CLASSES_ROOT;
//レジストリから文字コードの数値のリストを取得して配列に格納
RegKey := '\mime\database\codepage\';
Registry.OpenKey(RegKey, False);
Registry.GetKeyNames(slGCodePage);
Registry.CloseKey;
//mlangのオブジェクトを生成
MLang := CoCMultiLanguage.Create;
//レジストリから取得した文字コードのリストの説明文字を順番に取得
for i := 0 to slGCodePage.Count - 1 do begin
Registry.OpenKey(RegKey + slGCodePage[i], False);
//Windows Vista以降はレジストリから取得できないのでmlangの関数を使用
if CheckWin32Version(6, 0) then begin
MLang.GetCodePageInfo(StrToInt(slGCodePage[i]), MIMECPInfo);
strDescription := MIMECPInfo.wszDescription;
end else begin
strDescription := Registry.ReadString('Description');
end;
Registry.CloseKey;
slCode.Add(slGCodePage[i]);
slDistribute.Add(strDescription);
Application.ProcessMessages;
end;
finally
Registry.Free;
FreeAndNil(slGCodePage);
MLang := nil;
end;
end;
end.
02_MLang.dll の関数を使用した文字コード変換 |
Mlang.dll 内の ConvertINetString を使用して,コードページを変換するサンプルです.
ConvertINetString 関数の実行が成功しても,必ずしも変換に成功するとは限りません. |
|
図5
設計時画面 |
|
図6
実行中の画面
- [Read File] ボタンをクリックして,テキストファイルをメモリストリームに読み込む
- ボタンをクリックして文字コードを変換
|
|
図7
添付のテスト用テキストファイル |
|
図8
実行結果例
- EUC.txt を選択し,[to_Shift-S] を実行した結果できるファイル
|
リスト2
MLang.dll の関数を使用して,テキストファイルの文字のコードページを変換する |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
SpeedButton3: TSpeedButton;
SpeedButton4: TSpeedButton;
SpeedButton5: TSpeedButton;
SpeedButton6: TSpeedButton;
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
procedure SpeedButton3Click(Sender: TObject);
procedure SpeedButton4Click(Sender: TObject);
procedure SpeedButton5Click(Sender: TObject);
procedure SpeedButton6Click(Sender: TObject);
private
{ Private 宣言 }
ReadFileName : String;
SaveFileName : String;
ReadMemStream : TMemoryStream;
SaveMemStream : TMemoryStream;
function CharCodeConvert(SrcCode,DstCode: Integer; SrcStream,
DstStream: TMemoryStream): Boolean;
public
{ Public 宣言 }
end;
//ConvertINetStringはDelphi XEにはないので定義
function ConvertINetString (
lpdwMode: LPDWORD;
dwSrcEncoding: DWORD;
dwDstEncoding: DWORD;
lpSrcStr: PChar;
lpnSrcSize: pointer;
lpDstStr: PChar;
lpnDstSize: pointer): HRESULT; stdcall; external 'mlang.dll';
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// フォーム表示開始時の処理
//
// ReadStream : テキストファイルから読出した内容を保持
// SaveStream : 文字コード変換後の内容を保持
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
SpeedButton1.Enabled := False;
SpeedButton2.Enabled := False;
SpeedButton3.Enabled := False;
SpeedButton4.Enabled := False;
SpeedButton5.Enabled := False;
SpeedButton6.Enabled := False;
ReadMemStream := TMemoryStream.Create;
SaveMemStream := TMemoryStream.Create;
end;
//=============================================================================
// フォームを閉じる時の処理
// 使用したメモリストリームを解放
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(ReadMemStream);
FreeAndNil(SaveMemStream);
end;
//=============================================================================
// OpenDialogでテキストファイルを選択し
// 変換元のテキストをメモリストリームに読込む
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
OpenDialog1.InitialDir := ExpandFileName('../BeforeFile');
if OpenDialog1.Execute then begin
ReadFileName := OpenDialog1.FileName;
ReadMemStream.Clear;
ReadMemStream.LoadFromFile(ReadFileName);
SpeedButton1.Enabled := True;
SpeedButton2.Enabled := True;
SpeedButton3.Enabled := True;
SpeedButton4.Enabled := True;
SpeedButton5.Enabled := True;
SpeedButton6.Enabled := True;
end;
end;
//=============================================================================
// ECUへの変換
//=============================================================================
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_ECUを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_ECU.txt';
Screen.Cursor := crHourGlass;
try
CharCodeConvert(50932, 51932, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
finally
Screen.Cursor := crDefault;
end;
end;
//=============================================================================
// JISへの変換
//=============================================================================
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_JISを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_JIS.txt';
Screen.Cursor := crHourGlass;
try
CharCodeConvert(50932, 50222, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
finally
Screen.Cursor := crDefault;
end;
end;
//=============================================================================
// Shit-JISへの変換
//=============================================================================
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_S-JISを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_S-JIS.txt';
Screen.Cursor := crHourGlass;
try
CharCodeConvert(50932, 932, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
finally
Screen.Cursor := crDefault;
end;
end;
//=============================================================================
// UTF-16 Unicode(Big-Endian)への変換
//=============================================================================
procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_UNI-BEを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_UNI-BE.txt';
Screen.Cursor := crHourGlass;
try
CharCodeConvert(50932, 1201, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
finally
Screen.Cursor := crDefault;
end;
end;
//=============================================================================
// UTF-16 Unicode(Little-Endian)への変換
//=============================================================================
procedure TForm1.SpeedButton5Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_UNI-LEを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_UNI-LE.txt';
Screen.Cursor := crHourGlass;
try
CharCodeConvert(50932, 1200, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
finally
Screen.Cursor := crDefault;
end;
end;
//=============================================================================
// UTF-8Nへの変換
//=============================================================================
procedure TForm1.SpeedButton6Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_UTF-8Nを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_UTF-8N.txt';
Screen.Cursor := crHourGlass;
try
if CharCodeConvert(50932, 65001,ReadMemStream, SaveMemStream) then begin
SaveMemStream.SaveToFile(SaveFileName);
end;
finally
Screen.Cursor := crDefault;
end;
end;
//=============================================================================
// 文字コード変換関数
//
// [引数]
// SrcCode : 変換元の文字コードを指定
// DstCode : 変換後の文字コードを指定
// SrcStream : 変換元のテキストを格納したメモリストリーム
// DstStream : 変換後のテキストを格納するメモリストリーム
//
// 特に変換元の文字コードを日本語自動選択(SrcCode=50932)にした場合,結果がTrue
// でも正常に変換されているとは限らない.現在のシステムに依存する
//
// (1) 文字化けはないが,元の文字コードのまま
// (2) 別の文字コードになってしまう
// (3) 結果の文字コードは変化しているが,文字化けしている
//
// 等の場合がある
// 他の文字コード変換を経由する.また,変換元と変換後の文字コードを指定すると
// 変換がうまくいくこともある
//=============================================================================
function TForm1.CharCodeConvert(SrcCode, DstCode: Integer; SrcStream,
DstStream: TMemoryStream): Boolean;
var
SrcSize : Integer;
DstSize : Integer;
hr : HRESULT;
begin
SrcSize := SrcStream.Size;
DstSize := SrcSize * SizeOf(Char) + 2;
DstStream.Clear;
DstStream.SetSize(DstSize);
hr := ConvertINetString(nil,
SrcCode,
DstCode,
SrcStream.Memory,
@SrcSize,
DstStream.Memory,
@DstSize);
if (hr<>S_OK) or (DstSize=0) then begin
Result := False;
end else begin
Result := True;
end;
DstStream.SetSize(DstSize);
end;
end.
03_MultiLanguage_TLB.pas を使用した文字コードの変換 |
タイプライブラリの取り込みで作成した MultiLanguage_TLB.pas を使用した文字のコードページの変換サンプルです.IMLangConvertCharset インターフェイスの DoConversion 関数を使用します.
このサンプルも,コードページの組み合わせによっては,必ずしも文字のコードページに変換に成功するとは限りません. |
|
図9
設計時画面
|
|
図10
実行中の画面
- [Read File] ボタンをクリックして,テキストファイルをメモリストリームに読み込む
- ボタンをクリックして文字コードを変換
|
|
図11
添付テキストファイル
|
|
図12
実行結果例
- EUC.txt を選択して [to_Shift-JIS] を実行した結果
|
リスト3
MultiLanguage_TLB.pas を使用した文字のコードページの変換 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
SpeedButton3: TSpeedButton;
SpeedButton4: TSpeedButton;
SpeedButton5: TSpeedButton;
SpeedButton6: TSpeedButton;
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
procedure SpeedButton3Click(Sender: TObject);
procedure SpeedButton4Click(Sender: TObject);
procedure SpeedButton5Click(Sender: TObject);
procedure SpeedButton6Click(Sender: TObject);
private
{ Private 宣言 }
ReadMemStream : TMemoryStream;
SaveMemStream : TMemoryStream;
ReadFileName : String;
SaveFileName : String;
function CharCodeConvert(SrcCode,DstCode: Cardinal; SrcStream,
DstStream: TMemoryStream): Boolean;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses MultiLanguage_TLB;
{$R *.dfm}
//=============================================================================
// フォーム表示開始時の処理
//
// ReadStream : テキストファイルから読出した内容を保持
// SaveStream : 文字コード変換後の内容を保持
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
ReadMemStream := TMemoryStream.Create;
SaveMemStream := TMemoryStream.Create;
SpeedButton1.Enabled := False;
SpeedButton2.Enabled := False;
SpeedButton3.Enabled := False;
SpeedButton4.Enabled := False;
SpeedButton5.Enabled := False;
SpeedButton6.Enabled := False;
end;
//=============================================================================
// フォームを閉じる時の処理
// 使用したメモリストリームを解放
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(ReadMemStream);
FreeAndNil(SaveMemStream);
end;
//=============================================================================
// OpenDialog1でテキストファイルを選択し
// 変換元のテキストをメモリストリーム(ReadMemStream)に読込む
// 変換元のテキストファイルは,このアプリのフォルダの下のBeforeFileフォルダ
// 保存先は同様にすぐ下のChangedFileフォルダ
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
OpenDialog1.InitialDir := ExtractFilePath(Application.ExeName) + '../BeforeFile';
if OpenDialog1.Execute then begin
ReadFileName := OpenDialog1.FileName;
ReadMemStream.Clear;
ReadMemStream.LoadFromFile(ReadFileName);
SpeedButton1.Enabled := True;
SpeedButton2.Enabled := True;
SpeedButton3.Enabled := True;
SpeedButton4.Enabled := True;
SpeedButton5.Enabled := True;
SpeedButton6.Enabled := True;
end;
end;
//=============================================================================
// ECUへの変換
//=============================================================================
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_ECUを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_ECU.txt';
Screen.Cursor := crHourGlass;
CharCodeConvert(50932, 51932, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
Screen.Cursor := crDefault;
end;
//=============================================================================
// JISへの変換
//=============================================================================
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_JISを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_JIS.txt';
Screen.Cursor := crHourGlass;
CharCodeConvert(50932, 50222, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
Screen.Cursor := crDefault;
end;
//=============================================================================
// Shit-JISへの変換
//=============================================================================
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_S-JISを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_S-JIS.txt';
Screen.Cursor := crHourGlass;
CharCodeConvert(50932, 932, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
Screen.Cursor := crDefault;
end;
//=============================================================================
// UTF-16 Unicode(Big-Endian)への変換
//=============================================================================
procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_UNI-BEを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_UNI-BE.txt';
Screen.Cursor := crHourGlass;
CharCodeConvert(50932, 1201, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
Screen.Cursor := crDefault;
end;
//=============================================================================
// UTF-16 Unicode(Little-Endian)への変換
//=============================================================================
procedure TForm1.SpeedButton5Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_UTF-LEを付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_UNI-LE.txt';
Screen.Cursor := crHourGlass;
CharCodeConvert(50932, 1200, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
Screen.Cursor := crDefault;
end;
//=============================================================================
// UTF-8Nへの変換
//=============================================================================
procedure TForm1.SpeedButton6Click(Sender: TObject);
begin
//保存ファイル名を作成
//読出したファイル名の後ろに_to_UTF-8を付加
SaveFileName := ExpandFileName('../ChangedFile') + PathDelim
+ ChangeFileExt(ExtractFileName(ReadFileName), '')
+ '_to_UTF-8N.txt';
Screen.Cursor := crHourGlass;
CharCodeConvert(50932, 65001, ReadMemStream, SaveMemStream);
SaveMemStream.SaveToFile(SaveFileName);
Screen.Cursor := crDefault;
end;
//=============================================================================
// 文字コード変換関数
//
// [引数]
// SrcCode : 変換元の文字コードを指定
// DstCode : 変換後の文字コードを指定
// SrcStream : 変換元のテキストを格納したメモリストリーム
// DstStream : 変換後のテキストを格納するメモリストリーム
//
// 特に変換元の文字コードを日本語自動選択(SrcCode=50932)にした場合,結果がTrue
// でも正常に変換されているとは限らない.現在のシステムに依存する
//
// (1) 文字化けはないが,元の文字コードのまま
// (2) 別の文字コードになってしまう
// (3) 結果の文字コードは変化しているが,文字化けしている
//
// 等の場合がある
// 他の文字コード変換を経由する.また,変換元と変換後の文字コードを指定する
// あるいはInitializeのフラグを変えてみると変換がうまくいくこともある
//
// FMLang.InitializeのdwPropertyに使用可能な値以下の値
// const
// MLCONVCHARF_NONE = 0; デフォルト
// MLCONVCHARF_AUTODETECT = 1; 自動検出?
// MLCONVCHARF_NCR_ENTITIZE = 2; Unicodeマルチバイト専用
// MLCONVCHARF_NAME_ENTITIZE = 4; Unicodeマルチバイト専用
// MLCONVCHARF_USEDEFCHAR = 8; IMLangConvertCharsetでは未使用
// MLCONVCHARF_NOBESTFITCHARS = 16;
// MLCONVCHARF_DETECTJPN = 32; Shift-JISと日本語(EUC)
//=============================================================================
function TForm1.CharCodeConvert(SrcCode, DstCode: Cardinal; SrcStream,
DstStream: TMemoryStream): Boolean;
type
TCharArray = array of Byte;
var
MLang : IMLangConvertCharset;
dwProperty : Cardinal;
SrcSize : Cardinal;
DstSize : Cardinal;
SrcArray : TCharArray;
DstArray : TCharArray;
begin
Result := True;
MLang := CoCMLangConvertCharset.Create;
dwProperty := 0;
SrcSize := SrcStream.Size;
DstSize := SrcSize * SizeOf(Char) + 2;
SetLength(SrcArray, SrcSize);
SetLength(DstArray, DstSize);
SrcStream.Position := 0;
SrcStream.Read(SrcArray[0], SrcSize);
MLang.Initialize(SrcCode, DstCode, dwProperty);
MLang.DoConversion(SrcArray[0], SrcSize, DstArray[0], DstSize);
DstStream.Clear;
DstStream.Write(DstArray[0], DstSize);
if DstSize = 0 then begin
Result := False;
end;
DstStream.SetSize(DstSize);
DstStream.Position := 0;
MLang := nil;
end;
end.
04_MultiLanguage_TLB.pas を使用した文字コードの判別 |
上のサンプルと同じく,MultiLanguage_TLB.pas に実装されている IMultiLanguage2 インターフェイスの関数を使用して,文字のコードページの判定を行うサンプルです.
DetectInputCodepage という関数を使用します.このサンプルで取得する数値は,最初のサンプルで取得した文字コードページの値です.UTF-8 と UTF-8N の区別はつかないようです. |
Watercolor City で提供している EncodeDetect.pas 内の CheckEncoding 関数を利用すると,かなり高い精度でコードページが取得できるようです. |
|
図13
設計時画面 |
|
図14
添付のテキストファイル
- ここでは Shift-JIS のテキストファイルを選択
|
|
図15
実行結果
- Shit-JISのコードページの値である 932 を取得
|
リスト4
MultiLanguage_TLB.pas を使用した文字のコードページの判別 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
function DetectCodepage(SrcStream: TMemoryStream; dwFlag: Cardinal): Integer;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
MultiLanguage_TLB,
ComObj;
{$R *.dfm}
const
MLDETECTCP_NONE = 0; //デフォルト
MLDETECTCP_7BIT = 1; //7bitデータ
MLDETECTCP_8BIT = 2; //8bitデータ
MLDETECTCP_DBCS = 4; //ダブルバイト
MLDETECTCP_HTML = 8; //HTMLページ
MLDETECTCP_NUMBER = 16; //未実装
//=============================================================================
// OpenDialog1でテキストファイルを選択し
// 調査対象のテキストをメモリストリーム(ReadMemStream)に読込む
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
ReadMemStream : TMemoryStream;
iCode : Integer;
begin
OpenDialog1.InitialDir := ExpandFileName('../BeforeFile');
if OpenDialog1.Execute then begin
ReadMemStream := TMemoryStream.Create;
try
ReadMemStream.Clear;
ReadMemStream.LoadFromFile(OpenDialog1.FileName);
iCode := DetectCodepage(ReadMemStream, MLDETECTCP_NONE);
MessageBox(Handle, PChar(IntToStr(iCode)), '文字コード', MB_ICONINFORMATION);
finally
FreeAndNil(ReadMemStream);
end;
end;
end;
//=============================================================================
// 文字コード(コードページ)検出関数
// 引数のSrcStreamに格納されている文字コードを判定する関数
//
// このDetectCodePageでは結果を1つだけ返すようにしているが,複数の候補を結果と
// して返すことも可能.そのためには,FMLang.DetectInputCodepage関数の該当引数
// を配列として定義する必要がある
//=============================================================================
function TForm1.DetectCodepage(SrcStream: TMemoryStream;
dwFlag: Cardinal): Integer;
var
hr : HRESULT;
MultiLang2 : IMultiLanguage2;
SrcArray : array of Char;
SrcSize : Integer;
Encoding : TDetectEncodingInfo;
scores : Integer;
begin
//0だとShift-JIS(システムのデフォルト)も0で返すことがある
Result := -1;
//MultiLanguageオブジェクトの作成
MultiLang2 := CreateComObject(CLASS_CMultiLanguage) as IMultiLanguage2;
//使用するインターフェースをサポートしていれば実行
if MultiLang2 <> nil then begin
SrcSize := SrcStream.Size;
SetLength(SrcArray, SrcSize);
SrcStream.Position :=0;
SrcStream.Read(SrcArray[0], Length(SrcArray));
//取得したいコードページの候補数
//ここでは最初の候補のみ(つまり1つだけ)検出
scores := 1;
hr := MultiLang2.DetectInputCodepage(dwFlag,
0,
SrcArray[0],
SrcSize,
Encoding,
scores);
if hr = S_OK then begin
Result := Encoding.nCodePage;
end;
MultiLang2 := nil;
end;
SrcStream.Position := 0;
end;
end.
05_Delphi の関数を使用した文字コード変換 |
Delphi 2009 より前の Delphi のバージョンにも文字コード変換用の関数が用意されていました.
それらの 1 つ,UTF8ToString を使用したサンプルです.
UTF-8 または UTF-8N の文字コードのテキストを Shift-JIS のテキストに変換します. |
|
図16
設計時画面
|
|
図17
添付のテキストファイル |
|
図18
実行結果
- 実行結果は,UTF8Dst.txt という名前で保存される
- これは Shift-JIS コードのテキストファイル
|
リスト5
UTF8ToString 関数を使用した文字コード変換 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
Button1: TButton;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// UTF-8(UTF-8N)の文字列を現在の文字コードに変換(Shift-JIS)
// UTF-8(BOMなし)は変換に失敗するようである
// ここでは1行づつ実行しているが,1行づつ実行する必然性はない
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
SrcStrList : TStringList;
DstStrList : TStringList;
StrText : String;
i : Integer;
SaveFileName : String;
begin
OpenDialog1.InitialDir := ExtractFilePath(Application.ExeName);
if OpenDialog1.Execute then begin
SrcStrList := TStringList.Create;
DstStrList := TStringList.Create;
try
SrcStrList.LoadFromFile(OpenDialog1.FileName);
for i := 0 to SrcStrList.Count - 1 do begin
StrText := UTF8ToString(SrcStrList[i]);
DstStrList.Add(StrText);
end;
SaveFileName := ExtractFilePath(Application.ExeName) + 'UTF-8Dst.txt';
DstStrList.SaveToFile(SaveFileName);
finally
FreeAndNil(SrcStrList);
FreeAndNil(DstStrList);
end;
end;
end;
end.
06_日本語を含む URL 文字列のエンコードとデコード |
ファイルのテキストの文字コード変換ではありませんが,URL 文字列のエンコードとデコードの変換サンプルです.
HTTPApp.pas にもこの変換用の関数がありますが,文字コードの指定はできません.
下のサンプルは,Indy コンポーネントの TIdURI の関数を使用した変換です.
デコードには TIdURI.URLDecode 関数を,エンコードには TIdURI.ParamsEncode 関数を使用しています.これらはプロトコルの文字列が含まれる URL 文字列が対象です.TIdURI.URLEncode 関数は,プロトコルの文字列がないと変換に失敗します.
プロトコルの文字列がない場合のエンコードには,TIdURI.ParamsEncode を使用します. |
|
図19
設計時画面
|
|
図20
デコード
|
|
図21
エンコード
|
リスト6
TIdURI の関数を使用した,URL 文字列のエンコードとデコード |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses HTTPApp, IdURI;
{$R *.dfm}
// =============================================================================
// TIdURI.URLDecodeを使用したURL文字列のデコード
// usesにIdURIが必要
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
SrcStr : String;
DstStr : String;
begin
SrcStr := '%E5%8D%B0%E5%88%B7%E3%80%80%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF';
DstStr := TIdURI.URLDecode(SrcStr);
// 結果は'印刷 プリンタ'
MessageBox(Handle, PChar(DstStr), '結果', MB_ICONINFORMATION);
end;
// =============================================================================
// TIdURI.URLEncodeを使用したURL文字列のエンコード
// TIdURI.URLEncodeはプロトコルがある文字列をエンコードする
// プロトコルがないと変換に失敗する
// usesにIdURIが必要
// =============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
SrcStr : String;
DstStr : String;
Enc : TEncoding;
begin
SrcStr := 'http://www.test.com/印刷 プリンタ';
Enc := TEncoding.UTF8;
DstStr := TIdURI.URLEncode(SrcStr, Enc);
//漢字部分の結果は'%E5%8D%B0%E5%88%B7%E3%80%80%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF'
MessageBox(Handle, PChar(DstStr), '結果', MB_ICONINFORMATION);
end;
// =============================================================================
// TIdURI.ParamsEncodeを使用したURL文字列のエンコード
// usesにIdURIが必要
// =============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
SrcStr : String;
DstStr : String;
Enc : TEncoding;
begin
SrcStr := '印刷 プリンタ';
Enc := TEncoding.UTF8;
DstStr := TIdURI.ParamsEncode(SrcStr, Enc);
//結果は'%E5%8D%B0%E5%88%B7%E3%80%80%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF'
MessageBox(Handle, PChar(DstStr), '結果', MB_ICONINFORMATION);
end;
end.
文字コードの変換ではありませんが,異なる OS の間でテキストファイル等をやりとりする場合は,改行形式の違いにも注意する必要があります.また,アプリケーションによっても扱いが違う場合もあります.改行文字は,AdjustLineBreaks 関数を使用して変更することができます. |
OS |
改行形式 |
UNIX |
LF |
Windows |
CR + LF |
Machintosh |
CR |
|