2015-06-05 28 views
3

我有一个问题,将UTF-8编码的字符串转换回可用于delphi的东西。 该应用程序是用XE8编写的,正在Windows和OSX上部署。该应用程序分别在Windows和OSX上使用LimeLM API dll和dylib库。 一切工作正常在Windows上,我有问题是转换从OSX上的dylib库返回的字符串。我明白,所有进出dylib的字符串都需要使用UTF-8编码。 limeLM函数返回一个PWideChar值,我假设这个值是UTF编码的。但是,使用哪个函数来尝试将值转换为Delphi中可用的值并不重要,我所得到的只是垃圾。德尔福 - 从UTF-8转换字符串

下面是函数:

class function TurboActivate.GetFeatureValue(featureName: String): String; 
var 
    value : PWideChar; 
    FieldName : PWideChar; 
    tmpStr : String; 
begin 

    {$IFDEF MSWINDOWS} 
    FieldName := PwideChar(featureName); 
    {$ENDIF} 
    {$IFDEF MACOS} 
    FieldName := PWideChar(UTF8Encode(featureName)); 
    {$ENDIF} 


    value := GetFeatureValue(FieldName, nil); 

    if (value = '') then 
    begin 
     raise ETurboActivateException.Create('Failed to get feature value. the feature doesn''t exist.'); 
    end; 
    {$IFDEF MSWINDOWS} 
    Result := value; 
    {$ENDIF} 
    {$IFDEF MACOS} 
    tmpStr := UTF8ToString(value); 
    ShowMessage(tmpStr); 
    tmpStr := UTF8ToWideString(value); 
    ShowMessage(tmpStr); 
    tmpStr := UTF8ToUnicodeString(value); 
    ShowMessage(tmpStr); 
    tmpStr := UTF8ToAnsi(value); 
    ShowMessage(tmpStr); 

    Result := TmpStr; 
    {$ENDIF} 

end; 

肯定是有值进行解码, 值=“散汤湡獤杀浔汧浥楡⹬潣米䌴䅓㜭䙇ⵊ䵙㑗㈭呖ⵆ䥉倏䈭呎'#4

但tmpStr始终包含 '??????????ç?????? /'

任何帮助将衷心感谢。

回答

6

值= '散汤湡獤杀浔汧浥楡⹬潣米䌴䅓㜭䙇ⵊ䵙㑗㈭呖ⵆ䥉倏䈭呎' #4

这表示其具有你解释8位文本,推测为UTF-8编码,就好像它是UTF-16编码的。作为一个宽泛的规则,当你看到一个带有中文字符的UTF-16字符串时,它可能是一个正确解释的中文文本,或者是错误解释的8位文本。

当你正确解释文本为UTF-8,它是:

[email protected] 4CSA-7GFJ-YMW4-2VTF-II5Q-BNTA♥♦ 

我获得与此代码:

Writeln(TEncoding.UTF8.GetString(
    TEncoding.Unicode.GetBytes('散汤湡獤杀潯汧浥楡⹬潣m䌴䅓㜭䙇ⵊ䵙㑗㈭呖ⵆ䥉儵䈭呎́'#4))); 

做笔记但是,如果你看看字节数组由TEncoding.Unicode.GetBytes('散汤湡獤杀潯汧浥楡⹬潣m䌴䅓㜭䙇ⵊ䵙㑗㈭呖ⵆ䥉儵䈭呎́'#4)返回,那么你会看到它包含一个null。所以实际上这个字符串在电子邮件地址后以null结尾。

的问题从这里开始:

value : PWideChar; 
.... 
value := GetFeatureValue(FieldName, nil); 

事实上GetFeatureValue回报PAnsiChar。假设我正确解释了你的有效载荷是UTF-8编码的。

所以,你需要做以下修改:

  1. 变化GetFeatureValue返回类型为PAnsiChar
  2. value的类型更改为PAnsiChar
  3. value转换为使用UnicodeFromLocaleCharsTEncoding.GetString的字符串。

这可能是这样的:

var 
    Bytes: TBytes; 
.... 
SetLength(Bytes, StrLen(value)); 
Move(value^, Pointer(Bytes)^, Length(Bytes)); 
str := TEncoding.UTF8.GetString(Bytes); 

现在,在设置str[email protected]问题的数据。如上所述,数据包含一个空终止符,当它被错误地解释为UTF-16时,它无法终止该字符串。也就是说,文本4CSA-7GFJ-YMW4-2VTF-II5Q-BNTA♥♦来自缓冲区溢出。

+0

太棒了!谢谢你,大卫工作的一种享受。 – CapNemo101

+0

“TEncoding”的使用有点懒,因为它涉及一个堆分配和一个可以避免的mem副本。这将通过使用'UnicodeFromLocaleChars'来避免,但这只是一点点牵扯。所以我采取了懒惰的选择!但在生产代码中,我想我会使用'UnicodeFromLocaleChars'。 –

+0

或者,您可以使用'SetString()'将'PAnsiChar'数据复制到'UTF8String'变量中,然后将'UTF8String'直接分配给'UnicodeString'并让RTL为您处理转换。 –