我的行中有不需要的字符的备忘录,我想将它们全部删除。 这是我的代码:
var
del: Integer;
begin
for del := 0 to m0.Lines.Count - 1 do
begin
if (AnsiContainsStr(m0.Lines[del], 'remove me')) then
begin
m0.Lines.Delete(del);
end;
end;
end;
上面的代码仍然留下了一些我想删除的行。它只删除其中一些。 所以我尝试了另一种方法,这就是完成这项工作。
var
i, r, n: Integer;
begin
for i := 0 to m0.Lines.Count - 1 do
begin
if (AnsiContainsStr(m0.Lines[i], 'remove me')) then
begin
for r := 0 to m0.Lines.Count - 1 do
begin
if (AnsiContainsStr(m0.Lines[r], 'remove me')) then
begin
for n := 0 to m0.Lines.Count - 1 do
begin
if (AnsiContainsStr(m0.Lines[n], 'remove me')) then
begin
m0.Lines.Delete(n);
end;
end;
m0.Lines.Delete(r);
end;
end;
m0.Lines.Delete(i);
end;
end;
end;
我认为这是不对的,我不应该这样做。 如何优雅地完成这项工作?
答案 0 :(得分:8)
由于您的循环从0
运行到Count - 1
,因此将跳过删除行之后的行。
说明:假设第3行需要删除。您删除它,现在第4行将是第3行。循环变量i
将在下次运行时增加到4,因此永远不会评估新第3行。
解决方案:反向运行循环:
for i := m0.Lines.Count - 1 downto 0 do
答案 1 :(得分:3)
删除行时,可以更改所有后续行的索引。您尚未处理的行。您也会使循环失效,因为一旦删除了一行,for
循环的上限就越界了。您的第一个代码块读取超出列表末尾。
考虑一个包含3行的列表。您查看第一行索引0,然后选择删除它。现在剩下两行。接下来需要查看原始列表中的第1行和第2行,但它们现在编号为0和1.您的循环将无法执行此任务。您将跳过新索引为0的行。
标准技巧是以相反的顺序处理列表。然后,当您删除项目时,其索引已更改的行已被处理。在伪代码中:
for i := Count-1 downto 0 do
if DeleteThisItem(i) then
Delete(i);
关键是每当你使用索引i
时,你指的是在循环开始之前索引为i
的项目。
答案 2 :(得分:2)
此任务要求另一种方法。 for循环将动态地修改行索引并导致删除删除后的行,因为它们的索引会减少。
您应该使用while循环,而不是:
intIndex := 0; // starting at the first line
while intIndex < m0.Lines.Count do // iterating 'till the last line
begin
if (AnsiContainsStr(m0.Lines[intIndex], 'remove me')) then // if the current line contains the text
m0.Lines.Delete(intIndex) // delete that line and DON'T increase the index
else
Inc(intIndex); // increase the index
end;