【问题标题】:Convert hexadecimal strings from TBytes data in Delphi在 Delphi 中从 TBytes 数据转换十六进制字符串
【发布时间】:2015-12-06 23:22:43
【问题描述】:

我正在寻找一种简单的方法,从 TStringList(总是“Windows-1252”文本文件)中获取多行十六进制数据并将它们切割成记录块(每行可以有不同的长度)。

在 Delphi 7 中我使用过:

procedure DecodeLineAddr(const aLine: AnsiString; var ByteCount: integer; var Address:Cardinal; var RecType: Integer);
begin
//123 4567 89 0
//:10 4640 00 0000 0600 0200 fa00 004f 7800 1e00 fb00 88
 ByteCount:= StrToInt('$' + copy(aLine, 2, 2));
 Address  := StrToInt('$' + copy(aLine, 4, 4));
 RecType  := StrToInt('$' + copy(aLine, 8, 2));
end;

也就是说,只需从行中初始“块信息”中的正确位置复制字符,然后在前面加上'$',这样 StrToInt 就会将字符串解释为十六进制。

我逐行处理 - 所以很容易执行以下操作:

aLineAsTBytes:= TEncoding.ASCII.GetBytes(aStringLst[ndx]);

然后将 aLineAsTBytes 作为 TBytes 而不是 AnsiString 传递给 DecodeLineAddr。

我不清楚我应该如何解码各种字节(或如何适当地划分它们)以便使用适用于桌面和移动设备的代码返回正确的结果。

也就是说,如果使用 aLine:TBytes(而不是 AnsiString),则相当于:

ByteCount:= StrToInt('$' + copy(aLine, 2, 2));

(有没有更好/更快的方法来处理这个问题?)

TIA。

EdB

【问题讨论】:

  • 很难弄清楚你在问什么。肯定会有更快的方法来做到这一点。
  • 源数据来自哪里?对于桌面,我可以看到许多深奥的用例,您最终可能会得到笨拙的十六进制文本数据......但对于移动设备?你到底想在这里做什么?
  • @J... - 十六进制代码将从文件中加载,转换(并验证)为特定的二进制格式,通过蓝牙 LE 发送以更新微控制器的闪存。这来自 Android 或 iOS 设备。我使用 AnsiString 在 Windows 上通过 BT EDR 工作 - (不可否认)笨拙的十六进制数据是行业标准 - 无法摆脱它。这是我将 Delphi 7 程序移植到 XE8+ 移动设备的第一个主要端口 - 试图让我的头脑不使用 AnsiString!
  • @DavidHeffernan 我必须使用 hex-as-text 数据文件 - 我以前只是将 hex 文件读入 TStringList 并将每一行作为 AnsiString 处理 - 只需复制正确的字符的子集并转换为整数。我需要在移动设备上完成这项工作。从 TStringList 中取出一行并转换为 TBytes 很简单——我只是不确定如何使用 TBytes 版本并将等效的十六进制文本转换为整数——或者是否有更聪明的方法来完成这个。
  • @edbord 那么,我们讨论的是哪个行业标准?哪个微控制器?我提出的问题是你是否想重新发明轮子。

标签: delphi


【解决方案1】:

你已经在做的事情会起作用,但你需要做一些调整。最重要的是,将你的函数变成“字符串”类型而不是“AnsiString”类型,这意味着你必须将它转换。

移动设备字符串是从 0 开始的,因此在移动设备上,您需要从索引中减去 1。或者您可以使用我的 ocopy() 或 zcopy() 函数,它们在所有平台上都执行相同的操作。如果您正在处理旧的 Windows 代码,请使用 ocopy(),它会将基于 0 的字符串本质上视为基于 1 的字符串,从而更容易移植。

const
{$IFNDEF MSWINDOWS}
  STRZ = 1;
{$ELSE}
  STRZ = 0;
function zcopy(sString: string; iStartZeroBased: nativeint; iLength: nativeint):    string;
begin
  result := '';
  setlength(result, lesserof(iLength, length(sString)-iStartZerobased));
  movemem32(@result[strz], @sString[(strz+iStartZeroBased)],    length(result)*sizeof(char));
end;

function ocopy(sString: string; iStartOneBased: nativeint; iLength:     nativeint): string;
begin
  result := zcopy(sString, iStartOneBased-1, iLength);
end;

接下来,使用这段代码,它不是一个完全完整的解决方案,但会在移动设备上为您提供大部分 ansi-string 支持(围绕指针有一些轻微的警告)。但基本上你可以通过简单地将 ansistring 分配给字符串类型来转换字符串,反之亦然。我不得不从几个依赖项中破解它,所以我不保证它会开箱即用,但它应该非常接近。

unit iosbytestring;

interface

uses
  sysutils, classes;

{$IFNDEF MSWINDOWS}
const STRZERO = 0;
{$ELSE}
const STRZERO = 1;
{$ENDIF}

type
  Tiosansichar = packed record
  private
    b: byte;
    class function AnsiFromChar(c: char): byte;static;
    class function CharFromAnsi(b: byte): char;static;

  public
    function ToChar: char;
    function ToOrd: byte;
    class operator Implicit(const s: Tiosansichar): string;
    class operator Implicit(const s: Tiosansichar): char;
    class operator Implicit(const s: Tiosansichar): byte;
    class operator Implicit(const s: Tiosansichar): pointer;
  end;

  Tiosbytestring = record
  private
    Fbytes: TBytes;
    function GetChar(idx: nativeint): char;
    procedure SetChar(idx: nativeint; const Value: char);
    function GetAddrOf(idx: nativeint): pbyte;
    function getbyte(idx: nativeint): byte;
    procedure setbyte(idx: nativeint; const Value: byte);
  public
    property chars[idx: nativeint]: char read GetChar write SetChar;
    property bytes[idx: nativeint]: byte read getbyte write setbyte;
    property addrof[idx: nativeint]: pbyte read GetAddrOf;
    class operator Implicit(const s: TIOSByteString): string;
    class operator Implicit(const s: string): TIOSByteString;
    class operator Add(const s1,s2: TIOSByteString): TIOSByteSTring;
    class operator Add(const s1: string; const s2: TIOSByteString):     TIOSByteSTring;
    class operator Add(const s1: TIOSByteString; const s2: string): TIOSByteSTring;
    procedure FromString(s: string);
    function ToString: string;
    procedure SetLength(i: nativeint);
  end;
  TIOSAnsiString = TIOSByteString;
{$IFNDEF MSWINDOWS}
  ansistring = TIOSByteString;
  utf8string = TIOSByteString;
  widestring = string;
{$ENDIF}


implementation

{ iosbytestring }

class operator Tiosbytestring.Add(const s1: string;
const s2: TIOSByteString): TIOSByteSTring;
var
  ss2,ss3: string;
begin
  ss2 := s2.ToString;
  ss3 := s1+ss2;
  result.FromString(ss3);

end;

class operator Tiosbytestring.Add(const s1: TIOSByteString;
const  s2: string): TIOSByteSTring;
var
  ss1,ss3: string;
begin
  ss1 := s1.ToString;
  ss3 := ss1+s2;
  result.FromString(ss3);
end;




procedure Tiosbytestring.FromString(s: string);
begin
  Fbytes := TEncoding.ANSI.GetBytes(s);

end;

function Tiosbytestring.GetAddrOf(idx: nativeint): pbyte;
begin
  result := @Fbytes[idx];
end;

function Tiosbytestring.getbyte(idx: nativeint): byte;
begin
  result := Fbytes[idx-strzero];
end;

function Tiosbytestring.GetChar(idx: nativeint): char;
begin
  result := Tiosansichar.CharFromAnsi(Fbytes[idx-strzero]);
end;

class operator Tiosbytestring.Implicit(const s: TIOSByteString): string;
begin
  result := s.ToString;

end;

class operator Tiosbytestring.Implicit(const s: string): TIOSByteString;
begin
  result.FromString(s);
end;

procedure Tiosbytestring.setbyte(idx: nativeint; const Value: byte);
begin
  Fbytes[idx-strzero] := value;
end;

class operator Tiosbytestring.Add(const s1,
  s2: TIOSByteString): TIOSByteSTring;
var
  ss1,ss2,ss3: string;
begin
  ss1 := s1.ToString;
  ss2 := s2.ToString;
  ss3 := ss1+ss2;
  result.FromString(ss3);

end;

procedure Tiosbytestring.SetChar(idx: nativeint; const Value: char);
begin
  Fbytes[idx-strzero] := Tiosansichar.AnsiFromChar(value);
end;

procedure Tiosbytestring.SetLength(i: nativeint);
begin
  system.setlength(Fbytes,i);
end;

function Tiosbytestring.ToString: string;
begin
  result := TEncoding.ANSI.GetString(Fbytes);
end;

{ Tiosansichar }


class function Tiosansichar.AnsiFromChar(c: char): byte;
var
  s: string;
  te: TEncoding;
  b: TBytes;
begin
  s := c;

  b := TEncoding.ANSI.GetBytes(c);
  result := b[0];


end;


class function Tiosansichar.CharFromAnsi(b: byte): char;
var
  s: string;
  bytes: TBytes;
begin
  system.setlength(bytes, 1);
  bytes[0] := b;
  s := TEncoding.ANSI.GetString(bytes, 0, 1);
  result := s[low(s)];
end;

class operator Tiosansichar.Implicit(const s: Tiosansichar): char;
begin
  result := s.ToChar;
end;

class operator Tiosansichar.Implicit(const s: Tiosansichar): string;
begin
  result := s.ToChar;
end;

class operator Tiosansichar.Implicit(const s: Tiosansichar): pointer;
begin
  result := @s.b;
end;

class operator Tiosansichar.Implicit(const s: Tiosansichar): byte;
begin
  result := s.b;
end;

function Tiosansichar.ToChar: char;
begin
  result := CharFromAnsi(b);
end;

function Tiosansichar.ToOrd: byte;
begin
  result := b;
end;

end.

所以只需添加上面的单元,将其添加到您的 uses 子句中,神奇地,您将在您的移动平台上拥有一个 ansistring 类型。继续在 windows 上使用标准 ansistring 类型。

如果一切顺利...这就是您的代码 sn-p 最终的样子。

procedure DecodeLineAddr(const aLine: AnsiString; var ByteCount: integer; var     Address:Cardinal; var RecType: Integer);
var
  aLineWide: string;
begin
  aLineWide = aLine;
  //123 4567 89 0
  //:10 4640 00 0000 0600 0200 fa00 004f 7800 1e00 fb00 88
  ByteCount:= StrToInt('$' + ocopy(aLineWide, 2, 2));
  Address  := StrToInt('$' + ocopy(aLineWide, 4, 4));
  RecType  := StrToInt('$' + ocopy(aLineWide, 8, 2));
end;

【讨论】:

  • 如果您决定使用我的 ansistring 移动替代品,请密切注意 chars[] bytes[] 和 addrof[] 属性。例如,@mystring[5] 不起作用,但等效于 mystring.addrof[5] 来获取字符的地址。此外,您必须将任何使用 ord(mystring[5]) 的代码替换为 mystring[5].ToOrd
  • 我应该提一下,这一切都不是最佳的,而且我敢肯定会有一群巨魔对此抱怨......但它会完成工作。
  • 另外 setlength(myString) 不适用于我的手机 ansistring。改用 mystring.setlength() 。我想我应该考虑在该单元中创建一个全局函数。过程 SetLength(s: TiosByteString; newlength: nativeint) 开始 s.SetLength(newlength);结束;
  • 不错!那里有足够的东西来帮助我解决我在“解决这个问题”时遇到的很多问题。谢谢 - 这对推动我前进非常有用 - 从 D7 到更现代的东西。
  • 好!我很高兴看到人们从 Delphi 7 升级......也许有一天我能找到另一个 Delphi 工作,哈哈。我喜欢 Delphi,我希望它能重新站起来,让更多公司开始使用更新版本。
猜你喜欢
  • 2016-10-15
  • 2011-07-09
  • 2010-10-18
  • 2017-08-12
  • 1970-01-01
  • 1970-01-01
  • 2018-01-31
  • 2015-04-30
相关资源
最近更新 更多