Delphi для циклов и ошибок StringList

Хорошо, ребята, я пытался выяснить все возможные ошибки, которые совершаю, но сдаюсь ... Мне нужна помощь! Я пишу приложение для управления арендой для моей работы, и когда дата истекает, мое приложение удаляет имя из 2 текстовых файлов. Я написал 3 небольшие функции (процедуры), чтобы эта работа работала. Здесь:

Он загружается из файла date.dat и удаляет строку, содержащую имя сотрудника.

procedure remDate(emp: String);/// Removes employee from date file
var
  pos1, i: integer;
  dateList: TStringList;
begin
  dateList:=TStringList.Create;
  dateList.LoadFromFile('Data\dates.dat');
  for i:=0 to dateList.Count-1 do begin
    pos1:=AnsiPos(emp, dateList[i]);
    if pos1<>0 then begin
      dateList.Delete(i);
      dateList.SaveToFile('Data\dates.dat');
    end;
  end;
  dateList.Free;
end; //eo remDate

Он удаляет строку, содержащую имя сотрудника, из файла perm.dat.

procedure remPerm(emp: String);/// Removes employee from perm file
var
  pos1, i: integer;
  permList: TStringList;
begin
  permList:=TStringList.Create;
  permList.LoadFromFile('Data\perm.dat');
  for i:=0 to permList.Count-1 do begin
    pos1:=AnsiPos(emp, permList[i]);
    if pos1<>0 then begin
      permList.Delete(i);
      permList.SaveToFile('Data\perm.dat');
    end;
  end;
  permList.Free;
end; //eo remPerm

Этот склеивает их вместе. IsDue - это простая функция, которая сравнивает 2 даты и возвращает ИСТИНА, если дата сегодня или в прошлом.

procedure updatePerms;
var
  empList: TStringList;
  i: integer;
begin
  empList:=TStringList.Create;
  empList.LoadFromFile('Data\employes.dat');
  for i:=0 to empList.Count-1 do begin
    if isDue(empList[i]) then begin
      remDate(empList[i]);
      remPerm(empList[i]);  (*) Here is where the error points.
    end;
  end;
  empList.Free;
end;

Я получаю ошибку, когда доходит до remPerm в процедуре updatePerms. (*) Я получаю ошибку EStringList, выходящую за пределы (#). Многими попытками выяснилось, что это происходит только тогда, когда у сотрудника наступает срок родов сегодня. Прокомментируйте, если вам нужна дополнительная информация! Заранее спасибо, любая помощь очень ценится!


person Gab    schedule 22.11.2011    source источник
comment
Да и кстати, сотрудники могут быть только один раз в обоих файлах.   -  person Gab    schedule 22.11.2011


Ответы (1)


Проблема в том, что вы используете цикл for. Конечная точка цикла for оценивается только один раз при входе в цикл. На этом этапе у вас может быть 100 элементов, но как только вы начнете удалять, их станет меньше. Это приведет к ошибке выхода индекса списка за пределы.

Простое исправление - полностью изменить цикл for:

procedure remDate(emp: String);
/// Removes employee from date file
var
  pos1, i: integer;
  dateList: TStringList;
begin
  dateList := TStringList.Create;
  dateList.LoadFromFile('Data\dates.dat');
  for i := dateList.Count - 1 downto 0 do
  begin
    pos1 := AnsiPos(emp, dateList[i]);
    if pos1 <> 0 then
    begin
      dateList.Delete(i);
      dateList.SaveToFile('Data\dates.dat');
    end;
  end;
  dateList.Free;
end; // eo remDate

Это сработает, если сотрудник встречается более одного раза.

Однако, если сотрудник встречается только один раз, вы можете использовать break для раннего выхода из цикла:

procedure remDate(emp: String);
/// Removes employee from date file
var
  pos1, i: integer;
  dateList: TStringList;
begin
  dateList := TStringList.Create;
  dateList.LoadFromFile('Data\dates.dat');
  for i := 0 to dateList.Count - 1 do
  begin
    pos1 := AnsiPos(emp, dateList[i]);
    if pos1 <> 0 then
    begin
      dateList.Delete(i);
      dateList.SaveToFile('Data\dates.dat');
      Break; // <-- early exit
    end;
  end;
  dateList.Free;
end; // eo remDate

Другое решение - использовать цикл while.

person Gerry Coll    schedule 22.11.2011
comment
Большое спасибо! Вы не только исправили меня, но и заставили меня понять свою ошибку! Думал, что это могло быть так, но не видел этого далеко. Я изменил for i: = 0 на ... на downso, и это полностью сработало. Я также отметил перерыв; на будущее! Еще раз спасибо! - person Gab; 22.11.2011
comment
Я всегда использовал цикл while, когда мне нужно было удалить что-то из списка (список строк, список строк). Никогда не думал об использовании for..downto 0 для этого. +1 приятно - person Fabricio Araujo; 22.11.2011