全角チルダ/波ダッシュ問題に対応したTEncodingクラス

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.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください