AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Find and Replace in Textfile

Ein Thema von aegidos · begonnen am 20. Aug 2009 · letzter Beitrag vom 29. Sep 2009
Antwort Antwort
aegidos

Registriert seit: 30. Okt 2007
40 Beiträge
 
Delphi 2007 Professional
 
#1

Find and Replace in Textfile

  Alt 20. Aug 2009, 10:47
Hy alle zusammen.

Ich habe hier im Forum einen überaus hilfreichen Beitrag zum Suchen und Ersetzen gefunden:
Hier im Forum suchenReplaceInFile
Delphi-Quellcode:
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 }
Diese Funktion sucht das erste Auftauchen des Searchstrings und ersetzt diesen im gegebenen File durch den NewString.
Wie muss man denn diese Funktion anpassen um jedes Vorkommen des Searchstrings zu ersetzen?

Danke für die Hilfe!
Andi
  Mit Zitat antworten Zitat
Norbert987

Registriert seit: 27. Nov 2003
Ort: Aachen
74 Beiträge
 
Delphi 7 Professional
 
#2

Re: Find and Replace in Textfile

  Alt 20. Aug 2009, 10:53
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.
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#3

Re: Find and Replace in Textfile

  Alt 20. Aug 2009, 11:01
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
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#4

Re: Find and Replace in Textfile

  Alt 20. Aug 2009, 12:57
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:
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;
Falls Dir Flexibilität wichtiger als Geschwindigkeit ist, kannst Du die ReplaceFlags auch parametrisieren:
Delphi-Quellcode:
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;
Diese Routine lässt sich natürlich noch optimieren. Für beide Varianten benötigst Du die Unit 'SysUtils'
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
aegidos

Registriert seit: 30. Okt 2007
40 Beiträge
 
Delphi 2007 Professional
 
#5

Re: Find and Replace in Textfile

  Alt 21. Aug 2009, 07:30
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 !!!
  Mit Zitat antworten Zitat
Jens01

Registriert seit: 14. Apr 2009
670 Beiträge
 
#6

Re: Find and Replace in Textfile

  Alt 29. Sep 2009, 17:20
um ReplaceInFile für D2009 lauffähig zu bekommen, muß
SearchFor := StrAlloc(Length(SearchString) + 1); -> SearchFor := AnsiStrAlloc(Length(SearchString) + 1);
werden.
Jedenfalls bei mir.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:25 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz