Frage

Ich habe eine Funktion, die Aufgabe ist, um einen ADO Recordset in hTML:

class function RecordsetToHtml(const rs: _Recordset): WideString;

Und die Eingeweide der Funktion viel breiter String-Verkettung beinhaltet:

   while not rs.EOF do
   begin
      Result := Result+CRLF+
         '<TR>';

      for i := 0 to rs.Fields.Count-1 do
         Result := Result+'<TD>'+VarAsWideString(rs.Fields[i].Value)+'</TD>';

      Result := Result+'</TR>';
      rs.MoveNext;
    end;

Mit ein paar tausend Ergebnisse, die Funktion übernimmt, was jeder Benutzer sich anfühlen würde, ist zu lang zu laufen. Die Delphi Sampling Profiler zeigt, dass 99,3% von der Zeit ist in Wide Verkettung ausgegeben (@WStrCatN und @WstrCat).

denken kann jemand eine Möglichkeit, Wide Verkettung zu verbessern? Ich glaube nicht, Delphi 5, jede Art von String-Builder hat. Und Format unterstützt Unicode nicht.


Und sicher niemand versucht zu machen, um Wiesel: so tun, als Sie setzen die Schnittstelle:

IRecordsetToHtml = interface(IUnknown)
    function RecordsetToHtml(const rs: _Recordset): WideString;
end;

Update One

Ich dachte, eine IXMLDOMDocument zu verwenden, die HTML als XML aufzubauen. Aber dann wurde mir klar, dass die endgültige HTML xhtml wäre und nicht html - ein subtilen, aber wichtigen Unterschied

.

Update Zwei

Microsoft Knowledge Base-Artikel: Wie zur Verbesserung des String Concatenation Leistung

War es hilfreich?

Lösung 4

fand ich die beste Lösung. Die Open-Source HTMLParser für Delphi, hat einen Helfer TStringBuilder Klasse. Es wird intern zu bauen verwendet, was er DomStrings, das ist eigentlich ein Alias ??von WideString ist:

TDomString = WideString;

Mit ein wenig von seiner Klasse das Hantieren:

TStringBuilder = class
public
   constructor Create(ACapacity: Integer);
   function EndWithWhiteSpace: Boolean;
   function TailMatch(const Tail: WideString): Boolean;
   function ToString: WideString;
   procedure AppendText(const TextStr: WideString);
   procedure Append(const value: WideString);
   procedure AppendLine(const value: WideString);
   property Length: Integer read FLength;
end;

Die Eingeweide der Routine wird:

while not rs.EOF do
begin
   sb.Append('<TR>');

   for i := 0 to rs.Fields.Count-1 do
      sb.Append('<TD>'+VarAsWideString(rs.Fields[i].Value));

   sb.AppendLine('</TR>');

   rs.MoveNext;
end;

Der Code dann fühlt laufen unendlich afaster. Profilierungs zeigt viel Verbesserung; WideString die Manipulation und Längenzählung wurde vernachlässigbar. An seiner Stelle war FastMM eigenen internen Operationen.

Notizen

  1. Nizza Fang auf dem irrigen zwingt alle Strings in aktuelle Code-Seite (VarAsString statt VarAsWideString)
  2. Einige HTML-End-Tags sind optional; weggelassen diejenigen, die logisch keinen Sinn machen.

Andere Tipps

Wide ist von Natur aus langsam, weil sie für die COM-Kompatibilität implementiert wurden und COM Anrufe gehen. Wenn Sie den Code anschauen, wird es halten auf den String Neuzuweisung und rufen SysAllocStringLen () & C, die APIs von oleaut32.dll sind. Es verwendet nicht die Delphi-Speicher-Manager aber AFAIK es verwendet die COM-Speicher-Manager. Da die meisten HTML-Seiten nicht UTF-16 verwenden, können Sie bessere Ergebnisse mit dem nativen Delphi-String-Typ und eine String-Liste zu bekommen, obwohl Sie Konvertierung von UTF und der tatsächlichen Codepage sollten vorsichtig sein, und die Umwandlung Leistung Herabstufung auch . Auch sind Sie mit einer VarAsString () Funktion, dass wahrscheinlich eine Variante zu einem wandelt Ansi dann zu einem Wide umgewandelt. Überprüfen Sie, ob Ihre Version von Delphi eine VarAsWideString hat () oder etwas gleichermaßen Funktion, es zu vermeiden, oder verlassen sich auf Delphi automatische Konvertierung, wenn Sie sicher, dass Ihre Variante sein könnte niemals NULL sein.

Yup, Ihr Algorithmus ist eindeutig in O (n ^ 2).

Statt einen string zurückzukehren, versuchen, eine TStringList Rückkehr und ersetzen Sie die Schleife mit

   while not rs.EOF do
   begin
      Result.Add('<TR>');

      for i := 0 to rs.Fields.Count-1 do
         Result.Add( '<TD>'+VarAsString(rs.Fields[i].Value)+'</TD>' );

      Result := Result.Add('</TR>');
      rs.MoveNext;
    end;

Sie können dann speichern Sie Ihre Result mit TStringList.SaveToFile

Ich bin nicht in der Lage, die Zeit jetzt verbringen Sie den genauen Code zu geben.

Aber ich denke, das schnellste, was Sie tun können, ist:

  1. Schleife durch alle Fäden und insgesamt ihre Länge auch das Hinzufügen für die zusätzliche Tabellen-Tags Sie benötigen.

  2. Verwenden SetString eine Zeichenfolge der richtigen Länge zuzuordnen.

  3. Schleife durch alle die Saiten wieder und Verwendung der "Move" Verfahren auf den String an die richtige Stelle in der letzten Zeichenfolge zu kopieren.

Das Wichtigste ist, dass viele Verkettungen in einen String länger dauern und mehr wegen der ständigen Aufteilung und des Speichers zu befreien. Eine einzelne Zuordnung wird Ihre größte Zeit sparen.

wird nicht gezählt Wide Referenz, bedeutet jede Änderung eine String-Manipulation. Wenn Ihr Inhalt nicht Unicode ist codierter können Sie intern die native Zeichenfolge verwenden (Referenz gezählt) zu verketten String und es dann zu einem Wide konvertieren. Beispiel hierfür ist wie folgt:

var
  NativeString: string;
begin
   // ...
   NativeString := '';

   while not rs.EOF do
   begin
     NativeString := NativeString + CRLF + '<TR>';

     for i := 0 to rs.Fields.Count-1 do
       NativeString := NativeString + '<TD>'+VarAsString(rs.Fields[i].Value) + '</TD>';

     NativeString := NativeString + '</TR>';
     rs.MoveNext;
   end;

   Result := WideString(NativeString);
Encode Unicode UTF8String (als Referenz gezählt), sie verketten und schließlich UTF8String in Wide konvertieren:

Ich habe auch einen anderen Ansatz gesehen. Aber ich bin nicht sicher, ob zwei UTF8String direkt verkettet werden können. Die Zeit auf Codierung sollte ebenfalls berücksichtigt werden.

Wie auch immer, obwohl Wide Verkettung ist viel langsamer als die native String-Operationen. Aber es ist IMO noch akzeptabel. Zu viel Stimmung auf solche Art von Dingen, sollte vermieden werden. Im Ernst der Leistung bedenkt, sollten Sie dann Ihre Delphi ein Upgrade auf mindestens 2009. Die Kosten für ein Gerät zu erstehen ist für langfristige billiger als auf eine schwere Hacks tun alte Delphi.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top