inno 设置 - 帕斯卡中的无限循环,怎么来的



我写了一个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;

它曾经工作得很好,但只用替换了 FilePath 指定的文件的每一行上第一次出现的 OldLinePart。那是我添加重复循环的时候。逻辑是,当找不到更多匹配项时,Pos()返回 0。然后它应该继续到下一行。然而,事实是,循环无限地运行,我不知道为什么。我尝试在 if FoundAtPos > 0else 条款中添加一个 Break 语句,但没有运气......

编辑:显然已经很晚了。我正在用一个很长的字符串替换 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;

我用对 StringRereplace 的单个调用替换了你的循环。这可以防止(无限)循环并解决问题。
请注意,您在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;

让我知道这是否适合您。

现在应该使用 StringChangeEx 完成此操作。 很高兴它支持Unicode。 他通过删除旧函数来破坏旧脚本的方式并不好。 字符串替换不再编译;即使它是用于执行此操作的德尔菲函数。 StringChange 已被弃用。

最新更新