如何将AnsiChar转换为具有特定CodePage的UnicodeChar?

时间:2013-06-27 08:36:17

标签: delphi unicode

我生成纹理图集以在我的应用中呈现Unicode文本。源文本存储在ANSI代码页(1250,1251,1254,1257等)中。我希望能够从每个ANSI代码页生成所有符号。

以下是我期望的代码概要:

for I := 0 to 255 do
begin
  anChar := AnsiChar(I); //obtain AnsiChar

  //Apply codepage without converting the chars
  //<<--- this part does not work, showing:
  //"E2033 Types of actual and formal var parameters must be identical"
  SetCodePage(anChar, aCodepages[K], False);

  //Assign AnsiChar to UnicodeChar (automatic conversion)
  uniChar := anChar;

  //Here we get Unicode character index
  uniCode := Ord(uniChar);
end;

上面的代码不起作用(E2033),我不确定它是否是一个合适的解决方案。也许还有更短的版本。

在考虑特定代码页的情况下将AnsiChar转换为Unicode的正确方法是什么?

3 个答案:

答案 0 :(得分:3)

我会这样做:

function AnsiCharToWideChar(ac: AnsiChar; CodePage: UINT): WideChar;
begin
  if MultiByteToWideChar(CodePage, 0, @ac, 1, @Result, 1) <> 1 then
    RaiseLastOSError;
end;

我认为你应该避免使用字符串来进行字符操作。如果您事先知道需要支持哪些代码页,那么您可以将转换硬编码到以数组常量表示的查找表中。

请注意,ANSI代码页中定义的所有字符都映射到基本多语言平面中的Unicode字符,因此由单个UTF-16字符表示。因此,上面代码的大小假设。

但是,假设您正在制作并且此答案仍然存在,则单个字节表示ANSI字符集中的字符。这是许多字符集的有效假设,例如单字节西方字符集,如1252.但是有932(日语),949(Koren)等字符集是双字节字符集。对于那些代码页,您的整个方法都会崩溃。我的猜测是只希望支持单字节字符集。

如果您正在编写跨平台代码,则可以将MultiByteToWideChar替换为UnicodeFromLocaleChars

答案 1 :(得分:2)

您也可以一步完成所有角色。以下是代码页1250的示例:

var
  encoding: TEncoding;
  bytes: TBytes;
  unicode: TArray<Word>;
  I: Integer;
  S: string;
begin
  SetLength(bytes, 256);
  for I := 0 to 255 do
    bytes[I] := I;
  SetLength(unicode, 256);

  encoding := TEncoding.GetEncoding(1250); // change codepage as needed
  try
    S := encoding.GetString(bytes);
    for I := 0 to 255 do
      unicode[I] := Word(S[I+1]); // as long as strings are 1-based
  finally
    encoding.Free;
  end;
end;

答案 2 :(得分:0)

以下是我发现运作良好的代码:

var
  I: Byte;
  anChar: AnsiString;
  Tmp: RawByteString;
  uniChar: Char;
  uniCode: Word;
begin
  for I := 0 to 255 do
  begin
    anChar := AnsiChar(I);
    Tmp := anChar;
    SetCodePage(Tmp, aCodepages[K], False);
    uniChar := UnicodeString(Tmp)[1];
    uniCode := Word(uniChar);

    <...snip...>
  end;