Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2023-04

Is there a Pos() function for TBytes?

4 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bo Berglund

I am transferring data via serial comm and they wind up inside a TBytes dyn array.
Now I want to easily find a certain pattern of bytes inside that array, but how?

I have a cludge that does not feel right but works and I want to get it replaced by the "correct" way of doing it.

So what I have done so far is the following kind of thing using an AnsiString to supply the Pos() functionality:

var
  bData: TBytes;
  sData: AnsiString;
  p: integer;
begin
  GetSerialData(bData); //Load the array with incoming data
  SetLength(sData, Length(bData); //Prepare string to receive data
  Move(bData[0], sData[1], Length(bData)); //Copy all data
  p := Pos(pattern, sData);
  ...

I'd rather use some built-in function that is *not* using intermediate strings but can operate on the TBytes array directly.

I found this page:
https://www.freepascal.org/docs-html/rtl/system/copy.html

Here there is also reference to the other functions for strings: Delete (string and dyn array)
Copy (string and dyn array)
Insert (string and dyn array but limited to 255 elements, why?) Pos (string only..)

They describe what can be done with strings and in some cases dynamic arrays (like TBytes?), but for Pos() there is only string...

And Insert seems to have a limit of 255 elements, why?

What I need is a Pos(token) for TBytes where the token can be a single or multiple bytes in size (just like for strings).

Is there such a thing?

Bo Berglund Developer in Sweden
Michael Van Canneyt
to Bo Berglund
Bo Berglund wrote 42 lines
I am transferring data via serial comm and they wind up inside a TBytes dyn array. Now I want to easily find a certain pattern of bytes inside that array, but how? I have a cludge that does not feel right but works and I want to get it replaced by the "correct" way of doing it. So what I have done so far is the following kind of thing using an AnsiString to supply the Pos() functionality: var bData: TBytes; sData: AnsiString; p: integer; begin GetSerialData(bData); //Load the array with incoming data SetLength(sData, Length(bData); //Prepare string to receive data Move(bData[0], sData[1], Length(bData)); //Copy all data p := Pos(pattern, sData); ... I'd rather use some built-in function that is *not* using intermediate strings but can operate on the TBytes array directly. I found this page: https://www.freepascal.org/docs-html/rtl/system/copy.html Here there is also reference to the other functions for strings: Delete (string and dyn array) Copy (string and dyn array) Insert (string and dyn array but limited to 255 elements, why?) Pos (string only..) They describe what can be done with strings and in some cases dynamic arrays (like TBytes?), but for Pos() there is only string... And Insert seems to have a limit of 255 elements, why? What I need is a Pos(token) for TBytes where the token can be a single or multiple bytes in size (just like for strings). Is there such a thing?

Not that I am aware of, but I think it would be a welcome addition to one of the RTL units. I've been in need of such a function on multiple occasions, and had to resort to custom code each time.

Michael.

Bo Berglund
to Michael Van Canneyt
Michael Van Canneyt wrote 23 lines
> I found this page: > https://www.freepascal.org/docs-html/rtl/system/copy.html > > Here there is also reference to the other functions for strings: > Delete (string and dyn array) > Copy (string and dyn array) > Insert (string and dyn array but limited to 255 elements, why?) > Pos (string only..) > > They describe what can be done with strings and in some cases dynamic arrays > (like TBytes?), but for Pos() there is only string... > > And Insert seems to have a limit of 255 elements, why? > > What I need is a Pos(token) for TBytes where the token can be a single or > multiple bytes in size (just like for strings). > > Is there such a thing? Not that I am aware of, but I think it would be a welcome addition to one of the RTL units. I've been in need of such a function on multiple occasions, and had to resort to custom code each time.

FWIW, I threw together two overloaded Pos functions for a TBytes container like this (except I didn't name them Pos in order not to interfere with the RTL):

function PosInBytes(const Pattern, Target: TBytes): integer; overload;
function PosInBytes(const Pattern: byte; const Target: TBytes): integer;
overload;
implementation
function PosInBytes(const Pattern, Target: TBytes): integer;
var
  i, j, res: integer;
begin
  Result := -1;
  for i := 0 to Length(Target) - 1 - Length(Pattern) do
  begin
    if Target[i] = Pattern[0] then  //First byte of pattern found
    begin
      res := i;
      for j := 1 to Length(Pattern)-1 do
      begin
        if Target[i+j]  Pattern[j] then
        begin
          res := -1;
          break;
        end;
      end;
      if res >= 0 then break;
    end;
  end;
  Result := res;
end;
function PosInBytes(const Pattern: byte; Target: TBytes): integer;
var
  i: integer;
begin
  Result := -1;
  for i :=  0 to Length(Target) - 1 do
  begin
    if Target[i] = Pattern then
    begin
      Result := i;
      break;
    end;
  end;
end;
Bo Berglund Developer in Sweden
Alexey Torgashin
to Bo Berglund
function PosInBytes(const Pattern: byte; Target: TBytes): integer;

Let's use IndexByte standard procedure here?
Maybe also in the 1st overloaded code too?
Alex