【问题标题】:Delphi Berlin 10.1 OS X app Decode cyrillic for writing to hardDeviceDelphi Berlin 10.1 OS X app Decode cyrillic for write to hardDevice
【发布时间】:2018-03-14 17:33:47
【问题描述】:

我有 delphi 应用程序,我需要为 OS X 重写它。 此应用程序向/从 HID 设备写入/读取数据。

我在尝试从 mac 写入字符串时遇到问题。

这是我正在编写的行(来自 Windows 上的调试器):'Новый комплекс 1' 这很好用。同时,如果将其从调试器复制到某个地方,它将变为“Íîâûé êîìïëåêñ 1”。设备以西里尔字母显示它的书写方式。没关系。

当我尝试在 OS X 上重复此步骤时,设备显示无法读取的符号。但是,如果我从 Windows 示例中硬编码 'Íîâûé êîìïëåêñ 1' 就可以了。

给出一些提示。

如何在 Windows 上 一些代码:

 s:= 'Новый комлекс 1'

s:= AnsiToUtf8(ReplaceNull(s));

这里是 ReplaceNULL:

function ReplaceNull(const Input: string): string;
var
Index: Integer;
Res: String;
begin
Res:= '';
for Index := 1 to Length(Input) do
begin
if Input[Index] = #0 then
  Res:= Res + #$12
else
  Res:= Res + Input[Index];
end;
 ReplaceNull:= Res;
end;

我把这个字符串放到 Tstringlist 然后保存到文件:

ProgsList.SaveToFile(Mwork.pathLibs+'stream.ini', TEncoding.UTF8);

其他程序读取此列表,然后写入设备:

Progs:= TStringList.Create();

Progs.LoadFromFile(****);

s:= UTF8ToAnsi(stringreplace(Progs.Strings[i], #$12, #0, [rfReplaceAll,   rfIgnoreCase]));

然后将其写入设备。

所以写的那行看起来像这样:

"'þ5'#0'ÿ'#$11'Новый комплекс 1'#0'T45/180;55;70;85;90;95;100;T45/180'#0'ÿ'"

在 Mac 上我成功地得到了相同的字符串。但设备无法以西里尔文显示。

【问题讨论】:

  • 什么意思?使用统一码。还是您是 20 年前的时间旅行者?
  • “使用 unicode”是什么意思?
  • @artemk Delphi 字符串都是 unicode - 它们在 MacOS 和 Windows 上的显示都是一样的。 OSX 有完整的 unicode 支持。除非您正在使用已经编码为某种特定 ANSI 编码的某个地方的数据?否则,如果您遇到问题,请包含一些代码来演示该问题是什么。
  • 如果你不知道 Unicode 是什么,你需要停下来学习。
  • Progs.LoadFromFile(****); 应该是Progs.LoadFromFile(****, TEncoding.UTF8);

标签: macos delphi unicode decode delphi-10.1-berlin


【解决方案1】:

Delphi string 在所有平台上都以 UTF-16 编码。除非您在应用程序之外与非 Unicode 数据进行交互,否则无需对其进行转换。

话虽如此,如果您有一个以特定字符集编码的字节数组,则可以使用 Delphi 的 TEncoding.Convert() 方法将其转换为另一个字符集。您可以使用 TEncoding.GetEncoding() 方法获取特定字符集的 TEncoding 对象(如果不同于标准支持的字符集 - ANSI、ASCII、UTF-7、UTF-8 和 UTF-16 - 它们有自己的属性TEncoding 中的吸气剂)。

var
  SrcEnc, DstEnc: TEncoding;
  SrcBytes, ConvertedBytes: TBytes;
begin
  SrcBytes := ...; // Cyrillic encoded bytes
  SrcEnc := TEncoding.GetEncoding('Cyrillic'); // or whatever the real name is...
  try
    DstEnc := TEncoding.GetEncoding('Windows-1251');
    try
      ConvertedBytes := TEncoding.Convert(SrcEnc, DstEnc, SrcBytes);
    finally
      DstEnc.Free;
    end;
  finally
    SrcEnc.Free;
  end;
  // use ConvertedBytes as needed...
end;

更新:要将 Unicode 字符串编码为特定字符集,只需调用 TEncoding.GetBytes() 方法,例如:

s := 'Новый комлекс 1';
Enc := TEncoding.GetEncoding('Windows-1251');
try
  bytes := Enc.GetBytes(s);
finally
  Enc.Free;
end;

s := 'Новый комлекс 1';
bytes := TEncoding.UTF8.GetBytes(s);

您可以使用TEncoding.GetString() 将特定字符集中的字节解码回字符串,例如:

bytes := ...; // Windows-1251 encoded bytes
Enc := TEncoding.GetEncoding('Windows-1251');
try
  s := Enc.GetString(bytes);
finally
  Enc.Free;
end;

bytes := ...; // UTF-8 encoded bytes
s := TEncoding.UTF8.GetString(bytes);

【讨论】:

  • 对于第二位,对于硬编码字符串来说,重要的警告是源文件以 unicode 格式保存。 Delphi 对源文件默认为 ANSI,但当源文件包含非 ASCII 字符时提示保存为 unicode。
  • @J...:当然,当字符串数据在编译时是字符串文字时。但如果数据来自其他地方(文件、UI 等),那么你所说的就不适用了。
  • OP 似乎正在使用字符串文字,就像您的示例一样。认为这很重要。
  • 所以您建议将我的字符串从 MACOS 转换为字节,然后再转换为 windows-1251?
  • @artemk 我只是在指出如何进行转换。您是否应该这样做取决于您要完成的确切目标
【解决方案2】:

答案是下一个。 Delphi Berlin 10.1 使用 KOI8-R 和我的设备 - cp1251。 因为我想写俄语符号(西里尔文),所以我为来自 KOI8-R 和 cp1251 的符号创建了匹配表。

所以,我将 KOI8-R 中的字符串放入 cp1251 中。

简单代码:

 Dict:=TDictionary<String,String>.Create;
 Dict.Add(#$439,#$E9);//'й'
 Dict.Add(#$44E,#$FE);//'ю'
 Dict.Add(#$430,#$E0);//'а'

....

function tkoitocp.getCP1251Code(str:string):string;
var i:integer; res,key,val:string;  pair:Tpair<String,String>;
begin
res:='';
for i:=1 to length(str) do
 begin
   if dict.ContainsKey(str[i]) then
   begin
      pair:= dict.ExtractPair(str[i]);

      res:=res+pair.Value;
      dict.Add(pair.Key,pair.Value);
   end
   else
   res:=res+str[i];
 end;
 Result:=res;

end;

【讨论】: