StringReplace的二进制版本

时间:2010-06-23 22:54:42

标签: delphi delphi-2010 blob replace

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

我正在寻找一个像StringReplace一样工作的例程,但可以安全地用于可能包含空字节的blob。有人知道吗?

3 个答案:

答案 0 :(得分:4)

我猜StringReplace中的“Offending”函数是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;

答案 1 :(得分:1)

我没有进行过广泛的测试,但我认为此代码有效。

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;

答案 2 :(得分:0)

嗯。好像自己编写起来并不难。只需遍历缓冲区,直到找到第一个字节的匹配项。然后查看后续字节是否匹配。如果是这样,你找到它,现在更换。根据您的需要继续前进或退出。如果尺寸相同,显然更简单。如果没有,那么您可以设置第二个缓冲区并将基本缓冲区中的字节复制到新缓冲区中。