这看起来很简单。如果不根据您正在使用的数据分析代码,就很难确定(这总是一个好主意;如果您需要优化 Delphi 代码,请先尝试通过Sampling Profiler运行它,以了解您实际花费的地方你所有的时间,)但如果我不得不做出有根据的猜测,我猜你的瓶颈就在这一行:
Txt[Idx] := '0';
作为编译器对string
类型的安全写时复制语义保证的一部分,每次写入字符串的单个元素(字符)都涉及对UniqueString
例程的隐藏调用。这可以确保您不会更改其他东西或其他地方持有引用的字符串。
在这种特殊情况下,这不是必需的,因为您在此例程开始时获得了新鲜的字符串,并且您知道它是独一无二的。如果你小心的话,有办法绕过它。
清晰明确的警告:在没有确保你有一个唯一的字符串之前,不要做我将要解释的事情!UniqueString
完成此操作的最简单方法是手动 调用。此外,不要在循环期间执行任何可能将此字符串分配给任何其他变量的操作。当我们这样做时,它不会被视为普通字符串。 不注意此警告可能会导致数据损坏。
好的,既然已经解释过了,您可以使用指针直接访问字符串的字符,并绕过编译器的保护措施,如下所示:
procedure TForm1.btn1Click(Sender: TObject);
var
Txt: String;
Idx: Integer;
Tag: Boolean;
current: PChar; //pointer to a character
begin
Tag := False;
Txt := mem1.Text;
UniqueString(txt); //very important
if length(txt) = 0 then
Exit; //If you don't check this, the next line will raise an AV on a blank string
current := @txt[1];
dec(current); //you need to start before element 1, but the compiler won't let you
//assign to element 0
For Idx := 0 to Length(Txt) - 1 Do
Begin
inc(current); //put this at the top of the loop, to handle Continue cases correctly
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
,也没有重复计算偏移量,这意味着这可以快得多。
使用这样的指针时要非常小心。 编译器的安全检查是有充分理由的,并且在它们之外使用指针步骤。但有时,它们确实可以帮助您加快代码速度。再一次,在尝试这样的事情之前先配置文件。确保你知道是什么让事情变慢了,而不是仅仅认为你知道。如果结果是其他运行缓慢的东西,请不要这样做;而是找到真正问题的解决方案。