Бесконечный цикл в Паскале, как получилось? - PullRequest
0 голосов
/ 08 мая 2011

Я написал функцию Pascal для замены всей строки или только ее части в файле для использования в Inno Setup:

function ReplaceInFile(const FilePath, OldLinePart, Replacement: String;
                       DoReplaceWholeLine, IsCaseSensitive: Boolean): Boolean;
var
  FileLines:          TArrayOfString;
  Index:              Integer;
  FoundAtPos:         Integer;
  LeftOfOldLinePart:  String;
  RightOfOldLinePart: String;
  IsReplaced:         Boolean;
begin
  Result := False;
  if FileExists(FilePath) then begin
    LoadStringsFromFile(FilePath, FileLines);
    for Index := 0 to GetArrayLength(FileLines) - 1 do
    begin
      repeat
        FoundAtPos := 0;
        if IsCaseSensitive then
          FoundAtPos := Pos(OldLinePart, FileLines[Index])
        else
          FoundAtPos := Pos(Uppercase(OldLinePart), Uppercase(FileLines[Index]));
        if FoundAtPos > 0 then begin
          if DoReplaceWholeLine then begin
            FileLines[Index] := Replacement;
            IsReplaced := True;
          end
          else begin
            LeftOfOldLinePart := Copy(FileLines[Index], 1, FoundAtPos - 1);
            RightOfOldLinePart := Copy(FileLines[Index], FoundAtPos 
              + Length(OldLinePart), Length(FileLines[Index]) 
              - Length(LeftOfOldLinePart + OldLinePart));
            FileLines[Index] := LeftOfOldLinePart + Replacement + RightOfOldLinePart;
            IsReplaced := True;
          end;
        end;
      until FoundAtPos = 0;
    end;
    if IsReplaced then
      if SaveStringsToFile(FilePath, FileLines, False) then
        Result := True;
  end;
end;

Раньше она работала просто отлично, но заменилатолько первое вхождение OldLinePart в каждой строке файла, указанного в FilePath, с заменой.Именно тогда я добавил цикл повторения.Логика в том, что Pos() возвращает 0, когда больше не найдено.Затем следует перейти к следующей строке.Правда в том, что цикл продолжает идти бесконечно, и я понятия не имею, почему.Я попытался добавить оператор Break в предложение else для if FoundAtPos > 0, но не повезло ...

Редактировать: Очевидно, что уже поздно.Я заменял OldLinePart на очень длинную строку ... которая содержала то же слово.

Проблема решена следующим образом.

function ReplaceInFile(const FilePath, OldLinePart, Replacement: String; DoReplaceWholeLine, IsCaseSensitive: Boolean): Boolean;
var
  FileLines: TArrayOfString;
  Index: Integer;
  SearchLinePart: String;
  FoundAtPosition: Integer;
  SearchOffset: Integer;
  LeftOfOldLinePart: String;
  RightOfOldLinePart: String;
  IsReplaced: Boolean;
begin
  Result := False;
  if FileExists(FilePath) then
  begin
    LoadStringsFromFile(FilePath, FileLines);
    for Index := 0 to GetArrayLength(FileLines) - 1 do
    begin
      SearchOffset := 0;
      SearchLinePart := FileLines[Index];
      repeat
        FoundAtPosition := 0;
        if IsCaseSensitive then
          FoundAtPosition := SearchOffset + Pos(OldLinePart, SearchLinePart)
        else
          FoundAtPosition := SearchOffset + Pos(Uppercase(OldLinePart), Uppercase(SearchLinePart));
        if FoundAtPosition > SearchOffset then
        begin
          if DoReplaceWholeLine then
          begin
            FileLines[Index] := Replacement;
            IsReplaced := True;
            Break;
          end
          else
          begin
            LeftOfOldLinePart := '';
            RightOfOldLinePart := '';
            LeftOfOldLinePart := Copy(FileLines[Index], 1, FoundAtPosition - 1);
            RightOfOldLinePart := Copy(FileLines[Index], FoundAtPosition + Length(OldLinePart), Length(FileLines[Index]) - Length(LeftOfOldLinePart + OldLinePart));
            FileLines[Index] := LeftOfOldLinePart + Replacement + RightOfOldLinePart;
            IsReplaced := True;
            SearchOffset := Length(LeftOfOldLinePart + Replacement);
            SearchLinePart := RightOfOldLinePart;
          end;
        end;
      until FoundAtPosition <= SearchOffset;
    end;
    if IsReplaced then
      if SaveStringsToFile(FilePath, FileLines, False) then
        Result := True;
  end;
end;

Ответы [ 2 ]

2 голосов
/ 08 мая 2011

Я заменил ваш цикл одним вызовом StringReplace . Это предотвращает (бесконечный) цикл и решает проблему.
Обратите внимание, что у вас также была проблема с IsReplaced, например, если FileLines[4] был заменен, но не FilesLine[last], тогда ваш код не будет вызывать SaveStringsToFile.
Это также несколько упрощает код.

uses SysUtils;

function ReplaceInFile(const FilePath, OldLinePart, Replacement: String;
                       DoReplaceWholeLine, IsCaseSensitive: Boolean): Boolean;
var
  FileLines:          TArrayOfString;
  Index:              Integer;
  TempStr:            String;
  IsReplaced:         Boolean;
  Flags:              TReplaceFlags;
  IsReplacedAnywhere: Boolean;
begin
  Result := False;
  if FileExists(FilePath) then begin
    LoadStringsFromFile(FilePath, FileLines);
    IsReplacedAnywhere:= false;
    for Index := 0 to GetArrayLength(FileLines) - 1 do begin
      if DoReplaceWholeLine then begin
        IsReplaced := 
          IsCaseSensitive and (Pos(OldLinePart, FileLines[Index]) > 0) or 
          not(IsCaseSensitive) and 
           (Pos(Uppercase(OldLinePart), Uppercase(FileLines[Index])) > 0);
        if IsReplaced then FileLines[Index] := Replacement;
      end
      else begin
        Flags:= [rfReplaceAll];
        if not(IsCaseSensitive) then Flags:= Flags + [rfIgnoreCase];
        TempStr:= StringReplace(FileLines[Index], OldLinePart, Replacement
                                ,Flags);
        IsReplaced := (TempStr <> FileLines[Index]);
        if IsReplaced then FileLines[Index]:= TempStr;
      end; {else}
      IsReplacedAnywhere:= IsReplacedAnywhere or IsReplaced;
    end; {for Index}
    Result:= IsReplacedAnywhere 
             and SaveStringsToFile(FilePath, FileLines, False);
  end; {if}
end;

Дайте мне знать, если это работает для вас.

0 голосов
/ 08 сентября 2013

Теперь это должно быть сделано с помощью StringChangeEx. Приятно, что он поддерживает Unicode. Неприятно, как он ломает старые скрипты, удаляя старые функции. StringReplace больше не компилируется; хотя это функция Delphi для этого. StringChange уже устарел.

...