![]() |
Find and Replace in Textfile
Hy alle zusammen.
Ich habe hier im Forum einen überaus hilfreichen Beitrag zum Suchen und Ersetzen gefunden: ![]()
Delphi-Quellcode:
Diese Funktion sucht das erste Auftauchen des Searchstrings und ersetzt diesen im gegebenen File durch den NewString.
function TTestProgrammDlg.ReplaceInFile(const FileName, SearchString, NewString: AnsiString;
CaseSensitive: Boolean): Longint; { returns position of string in file or -1, if not found } const BufferSize = $8001; { 32K+1 bytes } var pBuf, pEnd, pScan, pPos: PAnsiChar; filesize: LongInt; bytesRemaining: LongInt; bytesToRead: Integer; F: file; SearchFor: PAnsiChar; oldMode: Word; begin Result := -1; { assume failure } // NEW (first line): if length of string to search and new string does not match, cancel. // Of course one could move the rest of the file accordingly instead. if (Length(SearchString) <> Length(NewString)) or (Length(SearchString) = 0) or (Length(FileName) = 0) then Exit; SearchFor := nil; pBuf := nil; { open file as binary, 1 byte recordsize } AssignFile(F, FileName); oldMode := FileMode; FileMode := fmOpenReadWrite; { NEW: access to read and write } Reset(F, 1); FileMode := oldMode; try { allocate memory for buffer and pchar search string } SearchFor := StrAlloc(Length(SearchString) + 1); StrPCopy(SearchFor, SearchString); if not caseSensitive then { convert to upper case } AnsiUpper(SearchFor); GetMem(pBuf, BufferSize); filesize := System.Filesize(F); bytesRemaining := filesize; pPos := nil; while bytesRemaining > 0 do begin { calc how many bytes to read this round } if bytesRemaining >= BufferSize then bytesToRead := Pred(BufferSize) else bytesToRead := bytesRemaining; { read a buffer full and zero-terminate the buffer } BlockRead(F, pBuf^, bytesToRead, bytesToRead); pEnd := @pBuf[bytesToRead]; pEnd^ := #0; { scan the buffer. Problem: buffer may contain #0 chars! So we treat it as a concatenation of zero-terminated strings. } pScan := pBuf; while pScan < pEnd do begin if not caseSensitive then { convert to upper case } AnsiUpper(pScan); pPos := StrPos(pScan, SearchFor); { search for substring } if pPos <> nil then begin { Found it! } Result := FileSize - bytesRemaining + Longint(pPos) - Longint(pBuf); // NEW: replace it Seek(F, Result); BlockWrite(F, PAnsiChar(NewString)^, Length(NewString)); Break; end; pScan := StrEnd(pScan); Inc(pScan); end; if pPos <> nil then Break; bytesRemaining := bytesRemaining - bytesToRead; if bytesRemaining > 0 then begin { no luck in this buffers load. We need to handle the case of the search string spanning two chunks of file now. We simply go back a bit in the file and read from there, thus inspecting some characters twice } Seek(F, FilePos(F) - Length(SearchString)); bytesRemaining := bytesRemaining + Length(SearchString); end; end; { While } finally CloseFile(F); if SearchFor <> nil then StrDispose(SearchFor); if pBuf <> nil then FreeMem(pBuf, BufferSize); end; end; { ScanFile } Wie muss man denn diese Funktion anpassen um jedes Vorkommen des Searchstrings zu ersetzen? Danke für die Hilfe! Andi |
Re: Find and Replace in Textfile
Hallo aegidos,
was spricht denn gegen StringReplace? StringReplace(strText, alt, neu, [rfReplaceAll]); du lädst deine Textdatei in eine TStringList und gehst dann Zeile für Zeile mit StringReplace durch. strText ist die Zeile aus der Textdatei, und alt wird dann nach neu ersetzt. |
Re: Find and Replace in Textfile
Hallo Andi,
ich verstehe Deine Frage nicht so ganz, da Du augenscheinlich den Source-Text verstanden hast. Du könntest z.b. das Break entfernen, den Dateizeiger um eine "Einheit" zurück setzen, und dann weiter machen. Wo klemmt es denn konkret? Gruß K-H |
Re: Find and Replace in Textfile
Die o.g. Routine funktioniert nicht, wenn der neue String eine andere Länge als der alte String aufweist. Reicht Dir das?
Ich würde den Vorschlag von Norbert987 aufgreifen:
Delphi-Quellcode:
Falls Dir Flexibilität wichtiger als Geschwindigkeit ist, kannst Du die ReplaceFlags auch parametrisieren:
Procedure ReplaceInFile (Const aFilename, aOldString, aNewString : String);
Var slData : TStringList; i : Integer; Begin slData := TStringlist.Create; Try slData.LoadFromFile (aFileName); For i:=0 to slData.Count - 1 do slData[i] := StringReplace (slData[i], aOldString, aNewString, [rfReplaceAll]); slData.SaveToFile(aFilename); Finally slData.Free; End End;
Delphi-Quellcode:
Diese Routine lässt sich natürlich noch optimieren. Für beide Varianten benötigst Du die Unit 'SysUtils'
Procedure ReplaceInFile (Const aFilename, aOldString, aNewString : String; aReplaceFlags : TReplaceFlags);
Var slData : TStringList; Begin slData := TStringlist.Create; Try slData.LoadFromFile (aFileName); slData.Text := StringReplace (slData.Text, aOldString, aNewString, aReplaceFlags); slData.SaveToFile(aFilename); Finally slData.Free; End End; |
Re: Find and Replace in Textfile
Hy alzaimar,
Danke für die Funktion. Geschwindigkeit ist mir an dieser Stelle doch wichtiger. Ich habe die erste Implementierung gewählt. funktioniert hervorragend , Danke !!! @p80286: Konkret hats daran geklemmt den Dateizeiger zurückzudrehen. Ich habe tatsächlich schon vorher versucht durch entfernen des Break die Funktion umzuschrieben. pPos habe ich dann wieder auf nil gesetzt aber ohne erfolg. Den Dateizeiger hatte ich da bei der betrachtung offensichtlich völlig vergessen. @Norbert987: Gute Idee, genau das ist es ja letztendlich auch geworden. Dachte anfangs einfach nur dass die Funktion die ich in dem anderen Thread gefunden habe schneller ist. Aber von Performance her nimmt sichs nicht viel. Außeßerdem war ich nur neugierig warum die Funktion die ich anfangs verwendet habe nur ein Auftauchen des Strings ersetzt und warum ich nicht fähig war sie auf ReplaceAllOccurrences umzutexten :-) Danke an Alle !!! |
Re: Find and Replace in Textfile
um ReplaceInFile für D2009 lauffähig zu bekommen, muß
SearchFor := StrAlloc(Length(SearchString) + 1); -> SearchFor := AnsiStrAlloc(Length(SearchString) + 1); werden. Jedenfalls bei mir. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:51 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz