StringReplace 的二进制版本

发布于 2024-09-06 15:47:21 字数 226 浏览 7 评论 0原文

我正在尝试在保存大量数据的 RawByteString 上运行 AnsiStrings.StringReplace,其中一些数据需要替换。它会起作用,除了在 StringReplace 内部它将我的字符串转换为 PAnsiChar,因此搜索一旦到达 blob 内的第一个 #0 字节就会结束。

我正在寻找一个与 StringReplace 类似的例程,但可以安全地在可能包含空字节的 blob 上使用。有人知道其中一个吗?

I'm trying to run AnsiStrings.StringReplace on a RawByteString holding a blob of data, some of which needs to be replaced. It would work, except that inside StringReplace it converts my string to a PAnsiChar, and so the search ends up bailing out as soon as it hits the first #0 byte inside the blob.

I'm looking for a routine that works just like StringReplace, but is safe to use on blobs that may contain null bytes. Does anyone know of one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我很OK 2024-09-13 15:47:21

我猜想 StringReplace 中的“违规”函数是 AnsiPos->AnsiStrPos

所以...我想缺少一个已经有效的解决方案,我会复制/粘贴 StringReplace 代码并将 AnsiPos 更改为其他内容。 (即 AnsiStrings.PosEx)

function RawByteStringReplace(const S, OldPattern, NewPattern: AnsiString;
  Flags: TReplaceFlags): AnsiString;
var
  SearchStr, Patt, NewStr: AnsiString;
  Offset: Integer;
begin
  //Removed the uppercase part...
  SearchStr := S;
  Patt := OldPattern;

  NewStr := S;
  Result := '';
  while SearchStr <> '' do
  begin
    Offset := AnsiStrings.PosEx(Patt, SearchStr);
    if Offset = 0 then
    begin
      Result := Result + NewStr;
      Break;
    end;
    Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
    NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
    if not (rfReplaceAll in Flags) then
    begin
      Result := Result + NewStr;
      Break;
    end;
    SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
  end;
end;

I'd guess the "Offending" function in StringReplace is AnsiPos->AnsiStrPos

So... I guess short of an already working solution, I'd copy/paste the StringReplace code and change AnsiPos for something else. (i.e. AnsiStrings.PosEx)

function RawByteStringReplace(const S, OldPattern, NewPattern: AnsiString;
  Flags: TReplaceFlags): AnsiString;
var
  SearchStr, Patt, NewStr: AnsiString;
  Offset: Integer;
begin
  //Removed the uppercase part...
  SearchStr := S;
  Patt := OldPattern;

  NewStr := S;
  Result := '';
  while SearchStr <> '' do
  begin
    Offset := AnsiStrings.PosEx(Patt, SearchStr);
    if Offset = 0 then
    begin
      Result := Result + NewStr;
      Break;
    end;
    Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
    NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
    if not (rfReplaceAll in Flags) then
    begin
      Result := Result + NewStr;
      Break;
    end;
    SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
  end;
end;
英雄似剑 2024-09-13 15:47:21

我没有进行广泛的测试,但我认为这段代码是有效的。

type
  TDynByteArray = packed array of byte;

procedure BufReplace(var BufStart: PByte; var BufLen: cardinal; const Find: TDynByteArray; const Replace: TDynByteArray);
var
  pos: PByte;
  BufEnd: PByte;
  i: Integer;
  Match: boolean;
begin
  {$POINTERMATH ON}
  if Find = nil then Exit;
  pos := BufStart;
  BufEnd := BufStart + BufLen;
  while pos < BufEnd do
  begin
    Match := false;
    if pos^ = Find[0] then
      if pos + length(Find) < BufEnd then
      begin
        Match := true;
        for i := 1 to high(Find) do
          if PByte(pos + i)^ <> Find[i] then
          begin
            Match := false;
            break;
          end;
      end;
      if Match then
      begin
        if length(Find) = length(Replace) then
          Move(Replace[0], pos^, length(Replace))
        else
        begin
          if length(Replace) < length(Find) then
          begin
            Move(Replace[0], pos^, length(Replace));
            MoveMemory(pos + length(Replace), pos + length(Find), BufEnd - pos - length(Find));
            dec(BufLen, length(Find) - length(Replace));
            ReallocMem(BufStart, BufLen);
          end
          else
          begin
            inc(BufLen, length(Replace) - length(Find));
            ReallocMem(BufStart, BufLen);
            MoveMemory(pos + length(Replace), pos + length(Find), BufEnd - pos - length(Find));
            Move(Replace[0], pos^, length(Replace))
          end;
        end;
        inc(pos, length(Replace));
      end
      else
        inc(pos);
  end;
end;

要测试它:

procedure TestIt;
var
  len: cardinal;
  a, b: TDynByteArray;
begin
  len := 16;
  GetMem(buf, len);
  FillChar(buf^, 16, $11);
  PByte(buf + 3)^ := $55;


  SetLength(a, 2);
  a[0] := $55;
  a[1] := $11;
  SetLength(b, 1);
  b[0] := $77;

  BufReplace(buf, len, a, b);
end;

I have not performed extensive testing, but I think that this code works.

type
  TDynByteArray = packed array of byte;

procedure BufReplace(var BufStart: PByte; var BufLen: cardinal; const Find: TDynByteArray; const Replace: TDynByteArray);
var
  pos: PByte;
  BufEnd: PByte;
  i: Integer;
  Match: boolean;
begin
  {$POINTERMATH ON}
  if Find = nil then Exit;
  pos := BufStart;
  BufEnd := BufStart + BufLen;
  while pos < BufEnd do
  begin
    Match := false;
    if pos^ = Find[0] then
      if pos + length(Find) < BufEnd then
      begin
        Match := true;
        for i := 1 to high(Find) do
          if PByte(pos + i)^ <> Find[i] then
          begin
            Match := false;
            break;
          end;
      end;
      if Match then
      begin
        if length(Find) = length(Replace) then
          Move(Replace[0], pos^, length(Replace))
        else
        begin
          if length(Replace) < length(Find) then
          begin
            Move(Replace[0], pos^, length(Replace));
            MoveMemory(pos + length(Replace), pos + length(Find), BufEnd - pos - length(Find));
            dec(BufLen, length(Find) - length(Replace));
            ReallocMem(BufStart, BufLen);
          end
          else
          begin
            inc(BufLen, length(Replace) - length(Find));
            ReallocMem(BufStart, BufLen);
            MoveMemory(pos + length(Replace), pos + length(Find), BufEnd - pos - length(Find));
            Move(Replace[0], pos^, length(Replace))
          end;
        end;
        inc(pos, length(Replace));
      end
      else
        inc(pos);
  end;
end;

To test it:

procedure TestIt;
var
  len: cardinal;
  a, b: TDynByteArray;
begin
  len := 16;
  GetMem(buf, len);
  FillChar(buf^, 16, $11);
  PByte(buf + 3)^ := $55;


  SetLength(a, 2);
  a[0] := $55;
  a[1] := $11;
  SetLength(b, 1);
  b[0] := $77;

  BufReplace(buf, len, a, b);
end;
树深时见影 2024-09-13 15:47:21

唔。看来自己写一个并不太难。只需迭代缓冲区,直到在第一个字节上找到匹配项。然后查看后续字节是否匹配。如果是这样,您已找到它,请立即更换。继续或退出,取决于您的需要。如果尺寸相同,显然更简单。如果没有,那么您可以设置第二个缓冲区并将字节从基本缓冲区复制到新缓冲区中。

Hmm. Seems like it couldn't be too hard to write your own. Just iterate through the buffer until you find a match on the first byte. Then see if the subsequent bytes match. If so, you found it, now replace. Keep going or quit, depending on what you need. Obviously simpler if the sizes are the same. If not, then you can set up a second buffer and copy bytes from the base buffer into the new buffer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文