【问题标题】:Convert string from codepage 1252 to 1250 and back将字符串从代码页 1252 转换为 1250 并返回
【发布时间】:2015-08-10 14:22:46
【问题描述】:

我使用 Delphi 7(基于 ANSI)。我需要在代码页之间转换字符串。我在网上找到了一个带有 multiByteToWideChar 和 wideCharToMultiByte 函数的解决方案。但正如我所见,它不起作用。我可以从 1250 转换为 1252,但另一种方式不太好。 这是我的测试代码:

procedure TForm1.Button1Click(Sender: TObject);

function ANSIToUTF8( text_ : string; codePage_ : cardinal ): string;
var
  w : WideString;
  sizeMB, sizeWC : integer;
begin
  if ( codePage_ <> CONST_codepage_UTF8 ) then
  begin
    // ANSI_XXXX to UTF16
    sizeMB := length( text_ );
    sizeWC := multiByteToWideChar( codePage_, 0, PAnsiChar( text_ ), sizeMB, nil, 0 );
    setLength( w, sizeWC );
    multiByteToWideChar( codePage_, 0, PAnsiChar( text_ ), sizeMB, PWideChar( w ), sizeWC );

    // UTF16 to UTF8
    sizeMB := wideCharToMultiByte( CONST_codepage_UTF8, 0, PWideChar( w ), sizeWC, nil, 0, nil, nil );
    setLength( result, sizeMB );
    wideCharToMultiByte( CONST_codepage_UTF8, 0, PWideChar( w ), sizeWC, PAnsiChar( Result ), sizeMB, nil, nil );
  end else
    result := text_;
end;

function UTF8ToANSI( text_ : string; codePage_ : cardinal ): string;
var
  w : WideString;
  sizeMB, sizeWC : integer;
begin
  if ( codePage_ <> CONST_codepage_UTF8 ) then
  begin
    // UTF8 to UTF16
    sizeMB := length( text_ );
    sizeWC := multiByteToWideChar( CONST_codepage_UTF8, 0, PAnsiChar( text_ ), sizeMB, nil, 0 );
    setLength( w, sizeWC );
    multiByteToWideChar( CONST_codepage_UTF8, 0, PAnsiChar( text_ ), sizeMB, PWideChar( w ), sizeWC );

    // UTF16 to ANSI_XXXX
    sizeMB := wideCharToMultiByte( codePage_, 0, PWideChar( w ), sizeWC, nil, 0, nil, nil );
    setLength( result, sizeMB );
    wideCharToMultiByte( codePage_, 0, PWideChar( w ), sizeWC, PAnsiChar( Result ), sizeMB, nil, nil );
  end else
    result := text_;
end;

  procedure testString( s_ : string; icp_ : cardinal );
  var
    sutf : string;
    s1250, s1252 : string;
    pc : pchar;

    function strToHex( s_ : string; ocp_ : cardinal ) : string;
    var
      i : integer;
    begin
      result := '';
      for i := 1 to length( s_ ) do
      begin
        if ( i > 1 ) then
          result := result + ', ';
        result := result + TStringUtility.byteToHexaDecimalStr( ord( s_[i] ) );
      end;
    end;

    procedure logInput;
    var
      s : string;
    begin
      s := 'Input (' + intToStr( icp_ ) + '): ' + strToHex( s_, icp_ );
      listbox1.items.add( s );
    end;

    procedure logOutput( ocp_ : cardinal );
    var
      s : string;
    begin
      s_ := utf8toansi( sutf, ocp_ );
      s := 'Output (' + intToStr( ocp_ ) + '): ' + strToHex( s_, ocp_ );
      listbox1.items.add( s );
    end;

  begin
    logInput;
    sutf := ansitoutf8( s_, icp_ );
    logOutput( 1250 );
    logOutput( 1252 );
    listbox1.items.add( '' );
  end;

begin
  testString( #$f5 + #$fa + #$fb, 1250 ); // õúû in 1250
  testString( #$6f + #$fa + #$75, 1252 ); // õúû in 1252
end;

记录的结果不是专家的结果。它显示api调用将字符串从1250转换为1252,但没有将1252转换为1250。我将默认代码页更改为1252,结果相同。

Input (1250): $f5, $fa, $fb
Output (1250): $f5, $fa, $fb
Output (1252): $6f, $fa, $75

Input (1252): $6f, $fa, $75
Output (1250): $6f, $fa, $75
Output (1252): $6f, $fa, $75

【问题讨论】:

  • 几十年前通过引入 Unicode 解决了这个问题。
  • FWIW、#$6F#$75 是纯 ASCII,在所有编码中可能都相同。但是用#$F5#$FB编码的码位在1252中似乎不存在,所以它们变成了纯ASCII值。

标签: delphi delphi-7


【解决方案1】:

您正在尝试的事情是不可能的。 1250 中的字符在 1252 中不存在,反之亦然。

考虑您问题中的示例字符。让我们从 1250 中的$f5 开始。即ő。现在,该角色在 1252 中不存在,因此系统无法执行您要求它执行的操作。相反,它尽其所能,并在 1252 中返回 $6f,即 o

那么当你从 1252 转换回 1250 时,就没有问题了,因为o 在 ASCII 范围内,可以正确转换。但是当然系统无法返回到ő,当您转到 1252 时,该信息已丢失。

如果您需要处理 1250 或 1252 中的文本,那么显而易见的解决方案是使用 Unicode。

【讨论】:

  • 我必须从 RichEdit 获取 RTF 内容,并将文本内容存储在 ANSI 中:( ansicpg 在标题处标记的代码页。
  • 嗯,这是一个不同的问题。我回答了你问的问题。正如您的问题所表达的那样,您正在尝试做的事情根本是不可能的。是什么让你决定 ANSI 是前进的方向。你为什么拒绝使用我在最后一段中建议的 Unicode?​​span>
  • 感谢您的回答。但是...正如我所见,1252 -> 1250 转换失败(输出字符代码相同)
  • 没有。正如我在回答中解释的那样。 ő 存在于 1250 中,但不存在于 1252 中。因此,一旦转换为 1252,o 就会被替换。这就是信息丢失的地方。您是否了解 1250(实际上是 1252)只有 256 个代码点?您似乎希望能够在 8 位类型中保存超过 256 个不同的值。鉴于你的名字是 bitman,如果你不介意我这么说的话,那感觉有点讽刺。
  • 啊。谢谢!到那时我强烈认为 $f5,$fa 和 $fb 低于 256... :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
  • 1970-01-01
  • 1970-01-01
  • 2018-12-24
  • 1970-01-01
相关资源
最近更新 更多