0

我编写了一个 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。然后它应该继续下一行。然而,事实是,循环一直在无限循环,我不知道为什么。我尝试在of 子句中添加一个Break语句,但没有运气......elseif 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;
4

2 回答 2

2

我用一次调用StringReplace替换了你的循环。这可以防止(无限)循环并解决问题。
请注意IsReplaced,如果 egFileLines[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;

让我知道这是否适合您。

于 2011-05-08T02:48:49.673 回答
0

现在应该使用 StringChangeEx 来完成。很高兴它支持 Unicode。他通过删除旧功能来破坏旧脚本的方式并不好。StringReplace 不再编译;即使它是执行此操作的 Delphi 函数。StringChange 已被弃用。

于 2013-09-08T19:19:16.120 回答