TEncodingクラスを使って文字コードの変換を行うと、全角チルダ/波ダッシュ問題が発生します。
MECSUtilsを使えば、全角チルダ/波ダッシュ問題を回避することができます。
例:文字コードがEUC-JPのファイルを読み込み、MECSUtilsを使って全角チルダ/波ダッシュ問題を回避する
var
SJISEncoding: TEncoding;
begin
SJISEncoding := TEncoding.GetEncoding(932);
Memo1.Lines.LoadFromFile('C:\test\sample.txt', SJISEncoding);
Memo1.Text := MecsMappingFix_CP932ToUnicode(Memo1.Text); //問題を引き起こす文字を再マッピング
しかし、毎回MECSUtilsの関数を呼ぶのは面倒ですし、関数を呼び忘れることもありそう。
そこで、TEncodingクラスを継承した全角チルダ/波ダッシュ問題を回避するクラスを作成してみました。
作成したクラスの内部では、MECSUtilsと同じ処理を行います。(ただし、「叱 (U+20B9F)」の文字は未対応です。)
shift_jisをサポートする「TSJISEncoding」クラス、ISO-2022-JP(JIS)をサポートする「TJISEncoding」クラス、EUC-JPをサポートする「TEUCJPEncoding」クラスがあります。
次のように使用できます。
var
SJISEncoding: TSJISEncoding;
begin
SJISEncoding := TSJISEncoding.Create;
Memo1.Lines.LoadFromFile('C:\test\sample.txt', SJISEncoding); //問題を引き起こす文字は自動的に再マッピング
以下、ソースコードです。
「叱 (U+20B9F)」の文字が未対応なので、いずれ修正したいと思っています。
unit JapaneseEncoding;
interface
uses System.SysUtils;
type
/// <summary>
/// shift_jis(シフト JIS)エンコーディングをサポートするクラスです。
/// </summary>
TSJISEncoding = class(TMBCSEncoding)
strict protected
function GetByteCount(Chars: PChar; CharCount: Integer): Integer;
overload; override;
function GetChars(Bytes: PByte; ByteCount: Integer; Chars: PChar;
CharCount: Integer): Integer; override;
function GetBytes(Chars: PChar; CharCount: Integer; Bytes: PByte;
ByteCount: Integer): Integer; overload; override;
public
constructor Create; override;
end;
/// <summary>
/// ISO-2022-JP(JIS)とEUC-JPエンコーディングをサポートするクラスの基底クラスです。
/// </summary>
TJIS_EUCJPEncoding = class(TMBCSEncoding)
strict protected
function GetByteCount(Chars: PChar; CharCount: Integer): Integer;
overload; override;
function GetChars(Bytes: PByte; ByteCount: Integer; Chars: PChar;
CharCount: Integer): Integer; override;
function GetBytes(Chars: PChar; CharCount: Integer; Bytes: PByte;
ByteCount: Integer): Integer; overload; override;
end;
/// <summary>
/// ISO-2022-JP(日本語 (JIS))エンコーディングをサポートするクラスです。
/// </summary>
TJISEncoding = class(TJIS_EUCJPEncoding)
public
constructor Create; override;
end;
/// <summary>
/// EUC-JPエンコーディングをサポートするクラスです。
/// </summary>
TEUCJPEncoding = class(TJIS_EUCJPEncoding)
public
constructor Create; override;
end;
implementation
{ MECSUtils }
/// <summary>
/// いわゆる "全角チルダ / 波ダッシュ問題" を引き起こす文字をインポート用に再マッピングします。
/// </summary>
procedure MecsMappingFix_CP932ToUnicode(Chars: PWideChar; CharCount: Integer);
var
i: Integer;
P: PWideChar;
begin
P := Chars;
for i := 1 to CharCount do
begin
case P^ of
#$2015: // U+2015: HORIZONTAL BAR -> U+2014: EM DASH
P^ := #$2014;
#$FFE3: // U+FFE3: FULLWIDTH MACRON -> U+203E: OVERLINE
P^ := #$203E;
end;
Inc(P);
end;
end;
/// <summary>
/// いわゆる "全角チルダ / 波ダッシュ問題" を引き起こす文字をインポート用に再マッピングします。
/// </summary>
procedure MecsMappingFix_JISX0208ToUnicode(Chars: PWideChar;
CharCount: Integer);
var
i: Integer;
begin
for i := 1 to CharCount do
begin
case Chars^ of
// Vender dependence
#$2014: // U+2014: EM DASH -> U+2015: HORIZONTAL BAR
Chars^ := #$2015;
#$203E: // U+203E: OVERLINE -> U+FFE3: FULLWIDTH MACRON
Chars^ := #$FFE3;
// Mapping Fix
#$2016: // U+2016: DOUBLE VERTICAL LINE -> U+2225: PARALLEL TO
Chars^ := #$2225;
#$2212: // U+2212: MINUS SIGN -> U+FF0D: FULLWIDTH HYPHEN-MINUS
Chars^ := #$FF0D;
#$301C: // U+301C: WAVE DASH -> U+FF5E: FULLWIDTH TILDE
Chars^ := #$FF5E;
#$00A2: // U+00A2: CENT SIGN -> U+FFE0: FULLWIDTH CENT SIGN
Chars^ := #$FFE0;
#$00A3: // U+00A3: POUND SIGN -> U+FFE1: FULLWIDTH POUND SIGN
Chars^ := #$FFE1;
#$00AC: // U+00AC: NOT SIGN -> U+FFE2: FULLWIDTH NOT SIGN
Chars^ := #$FFE2;
end;
Inc(Chars);
end;
end;
/// <summary>
/// いわゆる "JIS2004 問題 (新常用漢字問題)" を引き起こす文字を再マッピングします。
/// </summary>
procedure MecsMappingFix_JISX0213ToJISX0208(Chars: PWideChar;
CharCount: Integer);
var
i: Integer;
begin
for i := 1 to CharCount do
begin
case Chars^ of
#$525D:
Chars^ := #$5265;
#$5861:
Chars^ := #$586B;
#$9830:
Chars^ := #$982C;
end;
Inc(Chars);
end;
end;
/// <summary>
/// いわゆる "全角チルダ / 波ダッシュ問題" を引き起こす文字をエクスポート用に再マッピングします。"JIS2004 問題(新常用漢字問題)" も併せて修正します。
/// </summary>
procedure MecsMappingFix_UnicodeToCP932(Chars: PWideChar; CharCount: Integer);
var
i: Integer;
P: PWideChar;
begin
P := Chars;
for i := 1 to CharCount do
begin
case P^ of
// Vender dependence
#$2014: // U+2014: EM DASH -> U+2015: HORIZONTAL BAR
P^ := #$2015;
#$203E: // U+203E: OVERLINE -> U+FFE3: FULLWIDTH MACRON
P^ := #$FFE3;
// Mapping Fix
#$2011, // U+2011: NON-BREAKING HYPHEN -> U+002D: HYPHEN-MINUS
#$2012, // U+2012: FIGURE DASH -> U+002D: HYPHEN-MINUS
#$2013: // U+2013: EN DASH -> U+002D: HYPHEN-MINUS
P^ := #$002D;
#$2212, // U+2212: MINUS SIGN -> U+FF0D: FULLWIDTH HYPHEN-MINUS
#$FE58, // U+FE58: SMALL EM DASH -> U+FF0D: FULLWIDTH HYPHEN-MINUS
#$FE63: // U+FE63: SMALL HYPHEN-MINUS -> U+FF0D: FULLWIDTH HYPHEN-MINUS
P^ := #$FF0D;
end;
Inc(P);
end;
MecsMappingFix_JISX0213ToJISX0208(Chars, CharCount);
end;
/// <summary>
/// いわゆる "全角チルダ / 波ダッシュ問題" を引き起こす文字をエクスポート用に再マッピングします。"JIS2004 問題(新常用漢字問題)" も併せて修正します。
/// </summary>
procedure MecsMappingFix_UnicodeToJISX0208(Chars: PWideChar;
CharCount: Integer);
var
i: Integer;
P: PWideChar;
begin
P := Chars;
for i := 1 to CharCount do
begin
case P^ of
// Vender dependence
#$2014: // U+2014: EM DASH -> U+2015: HORIZONTAL BAR
P^ := #$2015;
#$203E: // U+203E: OVERLINE -> U+FFE3: FULLWIDTH MACRON
P^ := #$FFE3;
// Mapping Fix
#$2011, // U+2011: NON-BREAKING HYPHEN -> U+002D: HYPHEN-MINUS
#$2012, // U+2012: FIGURE DASH -> U+002D: HYPHEN-MINUS
#$2013: // U+2013: EN DASH -> U+002D: HYPHEN-MINUS
P^ := #$002D;
#$2225: // U+2225: PARALLEL TO -> U+2016: DOUBLE VERTICAL LINE
P^ := #$2016;
#$FE58, // U+FE58: SMALL EM DASH -> U+2212: MINUS SIGN
#$FE63, // U+FE63: SMALL HYPHEN-MINUS -> U+2212: MINUS SIGN
#$FF0D: // U+FF0D: FULLWIDTH HYPHEN-MINUS -> U+2212: MINUS SIGN
P^ := #$2212;
#$FF5E: // U+FF5E: FULLWIDTH TILDE -> U+301C: WAVE DASH
P^ := #$301C;
#$FFE0: // U+FFE0: FULLWIDTH CENT SIGN -> U+00A2: CENT SIGN
P^ := #$00A2;
#$FFE1: // U+FFE1: FULLWIDTH POUND SIGN -> U+00A3: POUND SIGN
P^ := #$00A3;
#$FFE2: // U+FFE2: FULLWIDTH NOT SIGN -> U+00AC: NOT SIGN
P^ := #$00AC;
end;
Inc(P);
end;
MecsMappingFix_JISX0213ToJISX0208(Chars, CharCount);
end;
{ TSJISEncoding }
constructor TSJISEncoding.Create;
begin
inherited Create(932);
end;
function TSJISEncoding.GetByteCount(Chars: PChar; CharCount: Integer): Integer;
begin
MecsMappingFix_UnicodeToCP932(Chars, CharCount);
Result := inherited;
end;
function TSJISEncoding.GetBytes(Chars: PChar; CharCount: Integer; Bytes: PByte;
ByteCount: Integer): Integer;
begin
MecsMappingFix_UnicodeToCP932(Chars, CharCount);
Result := inherited;
end;
function TSJISEncoding.GetChars(Bytes: PByte; ByteCount: Integer; Chars: PChar;
CharCount: Integer): Integer;
begin
Result := inherited;
MecsMappingFix_CP932ToUnicode(Chars, CharCount)
end;
{ TJIS_EUCJPEncoding }
function TJIS_EUCJPEncoding.GetByteCount(Chars: PChar;
CharCount: Integer): Integer;
begin
MecsMappingFix_UnicodeToJISX0208(Chars, CharCount);
Result := inherited;
end;
function TJIS_EUCJPEncoding.GetBytes(Chars: PChar; CharCount: Integer;
Bytes: PByte; ByteCount: Integer): Integer;
begin
MecsMappingFix_UnicodeToJISX0208(Chars, CharCount);
Result := inherited;
end;
function TJIS_EUCJPEncoding.GetChars(Bytes: PByte; ByteCount: Integer;
Chars: PChar; CharCount: Integer): Integer;
begin
Result := inherited;
MecsMappingFix_JISX0208ToUnicode(Chars, CharCount)
end;
{ TJISEncoding }
constructor TJISEncoding.Create;
begin
inherited Create(50222);
end;
{ TEUCJPEncoding }
constructor TEUCJPEncoding.Create;
begin
inherited Create(20932);
end;
end.