//字符串替换函数
//作者 QQ 287412388
//本代码,可以随意拷贝,修改使用,如果发现问题,请通知我.
//2011-09-09 14:18
function _stringReplace_(const Src,OldStr,NewStr:string):string;
const
DEFAULT_LIST_BUFF_SIZE = 2048;
type
PDataList=^TDataList;
TDataList=record
Buff:Pointer;
Len:Integer;
Next:PDataList;
Position:Integer;
//索引范围
Start:Integer;
Tail:Integer;
end;
PDataNode=^TDataNode;
TDataNode=record
Position:Integer;
Len:Integer;
BegPos:Integer;
NewPos:Integer;
end;
var
Node,Header:PDataList;
NewStr_Size,OldStr_Size:Integer;
function NewDataNode(Len:Integer=4096):PDataList;
begin
New(Result);
GetMem(Result^.Buff,Len);
Result^.Len := Len;
Result^.Next := nil;
Result^.Position := 0;
end;
procedure FreeDataList(Data:pDataList);
var
TmpNode,Node:pDataList;
begin
Node := Data;
while(Node <> nil) do
begin
FreeMem(Node^.Buff);
TmpNode := Node;
Node := Node.Next;
Dispose(TmpNode);
end;
end;
procedure AddData(Value:Integer);
var
P:PInteger;
begin
if Node^.Position = DEFAULT_LIST_BUFF_SIZE then
begin
Node.Next := NewDataNode(DEFAULT_LIST_BUFF_SIZE * 4);
Node := Node.Next;
ZeroMemory(Node^.Buff,Node^.Len);
end;
P := PInteger(Node^.Buff);
Inc(P,Node^.Position);
P^ := Value;
Inc(Node^.Position);
end;
function getDataNode(Index:Integer;var Ref:Pointer):Integer;
var
ANode:PDataList;
PI:PInteger;
begin
Result := 0;
if Ref <> nil then
ANode := Ref
else
ANode := Header;
while(ANode <> nil) do
begin
if (Index>=ANode.Start) and (Index<=ANode.Tail) then
begin
PI := PInteger(ANode.Buff);
Inc(PI,(Index- ANode.Start));
Result := PI^;
Ref := ANode;
Break;
end
else ANode := ANode.Next;
end;
end;
procedure getDataNode_II(Index:Integer;var P1,P2:Integer;var Ref:Pointer);
var
ANode:PDataList;
PI:PInteger;
begin
if Ref <> nil then
ANode := Ref
else
ANode := Header;
while(ANode <> nil) do
begin
if (Index>=ANode.Start) and (Index<=ANode.Tail) then
begin
PI := PInteger(ANode.Buff);
Inc(PI,(Index - ANode.Start));
P1 := PI^;
if (Index+1)<=ANode.Tail then
begin
Inc(PI);
P2 := PI^;
Ref := ANode;
Exit;
end;
Break;
end
else ANode := ANode.Next;
end;
P2 := getDataNode(Index + 1,Ref);
end;
procedure FillDataNode(Index:Integer;PNode:PDataNode;var Ref:Pointer);
var
Position,NextPosition:Integer;
begin
getDataNode_II(Index,Position,NextPosition,Ref);
PNode^.Len := NextPosition - Position - OldStr_Size;
PNode^.BegPos := Position + OldStr_Size;
PNode^.Position := Position;
PNode^.NewPos := Position;
end;
procedure InternalCopyMemory(PD,PS:PChar;len:Integer);
begin
if Len = 0 then
Exit;
case Len of
1: PD^ := PS^;
2: PWORD(PD)^ := DWORD(PS^);
3: begin
PD^ := PS^;
(PD+1)^ := (PS+1)^;
(PD+2)^ := (PS+2)^;
end;
4: PInteger(PD)^ := PInteger(PS)^;
else
CopyMemory(PD,PS,Len);
end;
//\\
end;
procedure WriteDataII(PD:PChar;AReplaceCount:Integer);
var
PS:PChar;
Index:Integer;
P1:PDataNode;
NodeRef:Pointer;
//\\
TmpInt:Integer;
begin
NodeRef := nil;
New(P1);
for Index := 0 to AReplaceCount - 1 do
begin
if Index = 0 then
begin
TmpInt := getDataNode(Index+1,NodeRef);
P1^.Position := 1;
P1^.BegPos := 1;
P1^.Len := TmpInt - 1;
P1^.NewPos := TmpInt;
end
else
FillDataNode(Index,P1,NodeRef);
if Index > 0 then
begin
if P1^.BegPos < P1^.NewPos then
begin
if P1^.Len > 0 then
begin
PS := Pointer(Src);
Inc(PS,P1^.BegPos - 1);
InternalCopyMemory(PD,PS,P1^.Len);
Inc(PD,P1^.Len);
end;
if NewStr_Size > 0 then
begin
InternalCopyMemory(PD,Pointer(NewStr),NewStr_Size);
Inc(PD,NewStr_Size);
end;
end
else begin
if NewStr_Size > 0 then
begin
InternalCopyMemory(PD,Pointer(NewStr),NewStr_Size);
Inc(PD,NewStr_Size);
end;
if P1^.Len > 0 then
begin
PS := Pointer(Src);
Inc(PS,P1^.BegPos - 1);
InternalCopyMemory(PD,PS,P1^.Len);
Inc(PD,P1^.Len);
end;
end;
end
else begin
if P1^.Len > 0 then
begin
PS := Pointer(Src);
Inc(PS,P1^.BegPos - 1);
InternalCopyMemory(PD,PS,P1^.Len);
Inc(PD,P1^.Len);
end;
end;
end;//for end
Dispose(P1);
end;
var
OffSet,OutSize:Integer;
ReplaceCount:Integer;
PD:PChar;
Index:Integer;
begin
OffSet := 1;
NewStr_Size := Length(NewStr);
OldStr_Size := Length(OldStr);
Header := NewDataNode(DEFAULT_LIST_BUFF_SIZE * 4);
ZeroMemory(Header^.Buff,Header^.Len);
Node := Header;
AddData(1);//前插
ReplaceCount := 0;
while(true) do
begin
OffSet := PosEx(OldStr,Src,OffSet);
if OffSet > 0 then
begin
AddData(OffSet);
Inc(ReplaceCount);
Inc(OffSet);
end
else begin
AddData(Length(Src) + 1);
Break;
end;
end;
Index := 0;
Node := Header;
while(Node <> nil) do
begin
Node.Start := Index;
Node.Tail := Index + DEFAULT_LIST_BUFF_SIZE -1;
Index := Node.Tail + 1;
Node := Node.Next;
end;
//计算输出字符的长度
if ReplaceCount = 0 then
begin
Result := Src;
Exit;
end;
//分配输出缓冲区
OutSize := Length(Src) - OldStr_Size * ReplaceCount;
OutSize := OutSize + NewStr_Size * ReplaceCount;
SetLength(Result,OutSize);
//复制数据到输出缓冲区
PD := Pointer(Result);
WriteDataII(PD,ReplaceCount + 1);//-1 删除掉最后一条不计算
//释放内存块
FreeDataList(Header);
//\\
end;
//测试代码,仅供参考
procedure TForm1.Button1Click(Sender: TObject);
var
TmpStr:string;
FS:TFileStream;
D:DWORD;
I:Integer;
begin
D := getTickCount();
for I := 1 to 1000 do
TmpStr := _stringReplace_(src,'A','a');
D := GetTickCount() - D;
ShowMessage(IntToStr(D));
FS := TFileStream.Create('E:\Text.TXT',fmCreate);
FS.Write(TmpStr[1],Length(TmpStr));
FS.Free();
// getMem(PS,1024);
end;