看起来很简单。如果没有针对您正在使用的数据进行编程剖析(这总是一个好主意;如果您需要优化Delphi代码,请先通过Sampling Profiler运行它,以便了解实际花费时间的地方),很难确定,但是如果我必须做一个有根据的猜测,我会猜测您的瓶颈在这一行中:
Txt[Idx] := '0';
作为编译器对字符串类型安全写时复制语义的保证的一部分,对字符串中单个元素(字符)进行的每次写操作都涉及到对
UniqueString
例程的隐藏调用。这确保您不会更改其他地方某个东西持有引用的字符串。
在这种特殊情况下,这是不必要的,因为您在此例程的开始处获得了新的字符串,并且知道它是唯一的。如果小心,有一个解决方法。
明确而明确的警告:在确保拥有唯一字符串之前,请勿执行我即将解释的操作!最简单的方法是手动调用
UniqueString
。此外,在循环期间不要执行任何可能将此字符串分配给任何其他变量的操作。在我们这样做时,它不被视为普通字符串。不遵守此警告可能会导致数据损坏。
好了,现在已经解释清楚了,您可以使用指针直接访问字符串的字符并绕过编译器的保护,如下所示:
procedure TForm1.btn1Click(Sender: TObject);
var
Txt: String;
Idx: Integer;
Tag: Boolean;
current: PChar;
begin
Tag := False;
Txt := mem1.Text;
UniqueString(txt);
if length(txt) = 0 then
Exit;
current := @txt[1];
dec(current);
For Idx := 0 to Length(Txt) - 1 Do
Begin
inc(current);
If (current^ = '<') Then
Tag := True Else
If (current^ = '>') Then
Begin
Tag := False;
Continue;
end;
If Tag Then Continue;
If (not (current^ in [#10, #13, #32])) Then
current^ := '0';
end;
mem2.Text := Txt;
end;
这改变了比喻。我们不再将字符串视为数组进行索引,而是像磁带一样处理它,使用指针作为头部,每次向前移动一个字符,从头到尾扫描,并在适当时更改其下的字符。没有冗余的
UniqueString
调用,也没有重复计算偏移量,这意味着这种方法可以更快速地完成。
当使用指针时,请非常小心。编译器的安全检查是有充分理由的,而使用指针则超出了这些范畴。但有时,它们确实可以加速您的代码。再次强调,在尝试此类操作之前,请先进行性能分析。确保您知道哪些因素导致了速度下降,而不是仅凭想象。如果发现其他因素导致了速度下降,请不要使用此方法;相反,请找到解决真正问题的方法。
{$ZEROBASEDSTRINGS ON}
的 Delphi 版本,否则这将导致错误。 - LU RD