2

私はADORecordsetをhtmlに変換することを仕事としている関数を持っています:

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

そして、関数の内臓には、多くの広い文字列の連結が含まれます。

   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;

数千の結果が得られたため、ユーザーが感じると思われる関数の実行には時間がかかりすぎます。Delphi Sampling Profilerは、時間の99.3%@WStrCatNがワイドストリング連結(および)に費やされていることを示してい@WstrCatます。

誰もがワイドストリング連結を改善する方法を考えることができますか?Delphi5には文字列ビルダーはないと思います。また、FormatUnicodeをサポートしていません。


そして、だれもだまそうとしないことを確実にするために:あなたがインターフェースを実装しているふりをします:

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

アップデートワン

IXMLDOMDocumentHTMLをxmlとして構築するために、を使用することを考えました。しかし、それから私は、最終的なHTMLがそうxhtmlではなくhtml、微妙ではあるが重要な違いであることに気づきました。

アップデート2

Microsoftナレッジベースの記事:文字列連結のパフォーマンスを向上させる方法

4

5 に答える 5

2

WideString は、COM 互換性のために実装され、COM 呼び出しを通過するため、本質的に低速です。コードを見ると、文字列の再割り当てが続けられ、oleaut32.dll の API である SysAllocStringLen() & C が呼び出されます。それは Delphi メモリ マネージャを使用しませんが、AFAIK では COM メモリ マネージャを使用します。ほとんどの HTML ページは UTF-16 を使用しないため、ネイティブの Delphi 文字列型と文字列リストを使用すると、より良い結果が得られる場合がありますが、UTF と実際のコードページからの変換には注意が必要であり、変換によってパフォーマンスも低下します。 . また、おそらくバリアントをAnsiStringに変換する VarAsString() 関数を使用していますその後、WideString に変換されます。お使いのバージョンの Delphi に VarAsWideString() などの関数が含まれているかどうかを確認してください。バリアントが NULL にならないことが確実な場合は、Delphi の自動変換に依存してください。

于 2010-06-10T14:08:24.847 に答える
1

うん、あなたのアルゴリズムは明らかにO(n ^ 2)にあります。

を返す代わりに、を返し、ループを次のように置き換えてstringみてくださいTStringList

   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;

Resultその後、使用を保存できますTStringList.SaveToFile

于 2010-06-10T12:20:01.507 に答える
1

私は最善の解決策を見つけました。Delphi 用のオープン ソースHtmlParserには、ヘルパーTStringBuilderクラスがあります。これは、彼が s と呼ぶものを構築するために内部的に使用されますDomString。これは、実際には のエイリアスですWideString

TDomString = WideString;

彼のクラスを少しいじって:

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;

ルーチンの内臓は次のようになります。

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;

その後、コードは無限に速く実行されるように感じます。プロファイリングは大幅に改善されています。WideString操作と長さのカウントは無視できるようになりました。その代わりに、FastMM 独自の内部操作がありました。

ノート

  1. VarAsStringすべての文字列を (ではなくVarAsWideString)現在のコードページに誤って強制するのをうまくキャッチ
  2. 一部の HTML 終了タグはオプションです。論理的に意味をなさない省略されたもの。
于 2010-06-11T00:01:49.490 に答える
1

現在、正確なコードをお伝えする時間がありません。

しかし、あなたができる最速のことは次のとおりだと思います。

  1. すべての文字列をループし、それらの長さを合計して、必要なテーブル タグを追加します。

  2. SetString を使用して、適切な長さの文字列を 1 つ割り当てます。

  3. すべての文字列を再度ループし、「移動」手順を使用して、文字列を最終文字列の適切な場所にコピーします。

重要なことは、メモリの割り当てと解放が常に行われるため、文字列への多くの連結に時間がかかることです。単一の割り当ては、最大の時間節約になります。

于 2010-06-11T02:13:14.153 に答える
0

Widestring は参照カウントされません。変更は文字列操作を意味します。コンテンツが Unicode でエンコードされていない場合は、ネイティブ文字列 (参照カウント) を内部的に使用して文字列を連結し、Widestring に変換できます。例は次のとおりです。

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);

別のアプローチも見ました。UnicodeをUTF8Stringにエンコードし(参照がカウントされるため)、それらを連結し、最後にUTF8StringをWidestringに変換します。しかし、2 つの UTF8String を直接連結できるかどうかはわかりません。エンコードの時間も考慮する必要があります。

とにかく、Widestring 連結はネイティブの文字列操作よりもはるかに遅くなります。しかし、IMO はまだ許容範囲です。そのようなことを過度に調整することは避けるべきです。パフォーマンスを真剣に考慮して、Delphi を少なくとも 2009 にアップグレードする必要があります。ツールを購入するコストは、古い Delphi で大規模なハッキングを行うよりも長期的には安くなります。

于 2010-06-10T13:39:31.327 に答える