UNICODE/UTF-8とShift-JIS文字コード相互変換(2003/11/30)
Unicode(Little Endian/Big Endian),UTF-8/8Nの文字コードチェックとShift-JISとの相互変換をおこなうためのユニットです。
池田氏作jconvert [Copyright(C) 1998 EarthWave Soft(IKEDA Takahiro)]の使用を前提とした拡張ユニットとして使用します。
注1)
UTF8はWindows98以降で追加されたAPIを使用しているためWindows95では動作しないと思わます。
注2)
UNICODEは1バイト文字も2バイトに拡張しており、文字列中に#0を含むためString型では取り扱うことができません。そのため、UNICODEからSJISに変換する際はPWideChar型を,SJISからUNICODEに変換する際にはver渡しのTMemoryStreamを使用するものしました。
変換したものをファイルに保存する事を考えると、MemoryStreamに書き込んで貰ったほうが楽だと思わます。
sjisToUniLE(ms, s);
ms.SaveToFile(FileName);
で済んでしまいます...
使用する際は、Uses節にjconvertとjconvexを追加してください。jconvertのInCodeCheckの代りにInCodeCheckExを使用すると、文字コードがUnicodeかUTF-8かのチェックも出来るようになります。もっともまじめにチェックしているのはUTF-8だけで、UnicodeとUTF-8Nは先頭のBOMをチェックしているだけなので誤作動の可能性があります(^^;
ここから下をjconvex.pasとして保存し、ライブラリパスの通ったフォルダに保存して下さい。
unit jconvex;
interface
uses
Windows, SysUtils, jconvert, Classes;
const
UNILE_IN = 7; // Unicode Little Endian(Intel CPU)
UNIBE_IN = 8; // Unicode Big Endian
UTF8_IN = 9; // UTF8(TTF8NのBOM付き)
UTF8N_IN = 10;// UTF8N
UNILE_OUT = 7;
UNIBE_OUT = 8;
UTF8_OUT = 9;
UTF8N_OUT = 10;
// 拡張文字コードチェック
function InCodeCheckEx(const s: string): integer;
// UNICODE(Little Endian)をSJISに変換する
function uniLETosjis(const s: PWideChar): string;
// UNICODE(Big Endian)をSJISに変換する
function uniBETosjis(const s: PWideChar): string;
// UTF8をSJISに変換する
function Utf8Tosjis(const s: String): string;
// UTF8NをSJISに変換する
function Utf8NTosjis(const s: String): string;
// SJISをUNICODE(LE)に変換する
procedure sjisToUniLE(var ms: TMemoryStream; const s: string);
// SJISをUNICODE(BE)に変換する
procedure sjisToUniBE(var ms: TMemoryStream; const s: string);
// SJISをUNICODE(UTF8)に変換する
function sjisToUtf8(const s: string): string;
// SJISをUNICODE(UTF8N)に変換する
function sjisToUtf8N(const s: string): string;
implementation
// 拡張文字コードチェック
// UNICODEとUTF8をチェックし、そのどれらでもなかった場合には
// jconvertのInCodeCheckを戻り値にする
function InCodeCheckEx(const s: string): integer;
var
index, c, size: Integer;
utfk: Boolean;
begin
size := Length(s);
{ Size = 0 }
if size = 0 then
begin
Result := BINARY;
Exit;
end;
{ Unicodeをチェックする }
{ 先頭のBOMしかチェックしていないので誤作動の可能性あり }
if (size >= 2 ) then
begin
{ UNICODE(Little Endian)チェック }
if (s[1] = #$FF) and (s[2] = #$FE) then
begin
Result := UNILE_IN;
Exit;
end;
{ UNICODE(Big Endian)チェック }
if (s[1] = #$FE) and (s[2] = #$FF) then
begin
Result := UNIBE_IN;
Exit;
end;
end;
{ UTF-8をチェックする }
if size > 3 then
begin
{ UTF-8N(BOMあり)チェック }
{ 先頭のBOMしかチェックしていないので誤作動の可能性あり }
if (s[1] = #$EF) and (s[2] = #$BB) and (s[3] = #$BF) then
begin
Result := UTF8_IN;
Exit;
end;
end;
{UTF-8(BOMなし)チェック}
index := 1;
utfk := False;
while (index <= STRICT_CHECK_LEN) and (index < size - 4) do
begin
c := Ord(s[index]);
if (c in [$C0..$DF]) or (c > $EF) then
begin
utfk := False;
Break;
end;
if c in [0..$7F] then
begin
;
end else if c = $E0 then
begin
Inc(index);
c := Ord(s[index]);
if c in [$A0..$BF] then
begin
Inc(index);
c := Ord(s[index]);
if c in [$80..$BF] then
utfk := True
else begin
utfk := False;
Break;
end;
end else begin
utfk := False;
Break;
end;
end else if c in [$E1..$EF] then
begin
Inc(index);
c := Ord(s[index]);
if c in [$80..$BF] then
begin
Inc(index);
c := Ord(s[index]);
if c in [$80..$BF] then
utfk := True
else begin
utfk := False;
Break;
end;
end else begin
utfk := False;
Break;
end;
end else begin
utfk := False;
Break;
end;
Inc(index);
end;
{ 漢字があったらUTF }
if utfk then
Result := UTF8N_IN
{ UnicdeでもUTF8でもなければJconvertでチェック }
else
Result := InCodeCheck(s);
end;
function UniLETosjis(const s: PWideChar): string;
begin
Result := WideCharToString(s);
end;
function UniBETosjis(const s: PWideChar): string;
var
Pc: PChar;
c: char;
n: integer;
begin
Pc := PChar(s);
n := 0;
while True do
begin
if (Pc[n] = #0) and (Pc[n+1] = #0) then
Break;
c := Pc[n];
Pc[n] := Pc[n+1];
Pc[n+1] := c;
Inc(n, 2);
end;
Result := WideCharToString(PWideChar(Pc));
end;
procedure sjisToUniLE(var ms: TMemoryStream; const s: string);
var
PWs: PWideChar;
Len: integer;
begin
if not Assigned(ms) then
raise Exception.Create('無効なMemoryStream.');
Len := Length(s) * 2;
PWs := AllocMem(Len + 2);
try
StringToWideChar(s, PWs, Len);
ms.Write(#$FF#$FE, 2);
ms.Write(PWs^, Length(Pws) * 2);
finally
FreeMem(PWs);
end;
end;
procedure sjisToUniBE(var ms: TMemoryStream; const s: string);
var
PWs: PWideChar;
Pc: PChar;
len, n: integer;
Tc: Char;
begin
if not Assigned(ms) then
raise Exception.Create('無効なMemoryStream.');
Len := Length(s) * 2;
PWs := AllocMem(Len + 2);
try
StringToWideChar(s, PWs, Len);
Pc := PChar(PWs);
n := 0;
while n < len do
begin
Tc := (Pc+n)^;
(Pc+n)^ := (Pc+n+1)^;
(Pc+n+1)^ := Tc;
Inc(n, 2);
end;
ms.Write(#$FE#$FF, 2);
ms.Write(PWs^, Length(Pws) * 2);
finally
FreeMem(PWs);
end;
end;
function Utf8NTosjis(const s: string): string;
var
Len: integer;
OutStr: PWideChar;
SIn, SOut: string;
begin
Result := '';
// ゴミ防止
SIn := S + #0#0;
Len := MultiByteToWideChar(CP_UTF8, 0, PChar(SIn), Length(SIn), nil, 0);
if Len = 0 then
raise Exception.Create('UTF8の文字列変換に失敗しました.');
// Lenで良いはずだが、なぜかエラーとなるため2倍
OutStr := AllocMem(Len * 2);
try
MultiByteToWideChar(CP_UTF8, 0, PChar(SIn), Length(SIn), OutStr, Len);
WideCharToStrVar(OutStr, SOut);
Result := SOut;
finally
FreeMem(OutStr);
end;
end;
function Utf8Tosjis(const s: string): string;
var
s2: string;
begin
s2 := s;
Delete(s2, 1, 3);
Result := Utf8NTosjis(s2);
end;
function SjisToUtf8N(const s: string): string;
var
Len: integer;
InStr: PWideChar;
OutStr: PChar;
begin
Result := '';
Len := Length(s) * 2 + 2;
InStr := AllocMem(Len);
try
StringToWideChar(s, InStr, Len);
OutStr := AllocMem(Len);
try
WideCharToMultiByte(CP_UTF8, 0, InStr, Length(InStr) * 2, OutStr, Len, nil, nil);
Result := OutStr;
finally
FreeMem(OutStr);
end;
finally
FreeMem(InStr);
end;
end;
function SjisToUtf8(const s: string): string;
begin
Result := #$EF#$BB#$BF + SjisToUtf8N(s);
end;
end.