6

実行時にすべての文字列をTStringListに入れて、アプリケーションに言語翻訳を実装しました。

procedure PopulateStringList;
begin  
  EnglishStringList.Append('CAN_T_FIND_FILE=It is not possible to find the file');
  EnglishStringList.Append('DUMMY=Just a dummy record');
  // total of 2000 record appended in the same way
  EnglishStringList.Sorted := True; // Updated comment: this is USELESS!
end;

次に、次を使用して翻訳を取得します。

function GetTranslation(ResStr:String):String;
var
  iIndex : Integer;
begin
  iIndex := -1;
  iIndex :=  EnglishStringList.IndexOfName(ResStr);
  if iIndex >= 0 then
  Result :=  EnglishStringList.ValueFromIndex[iIndex] else
  Result := ResStr + ' (Translation N/A)';
end;

とにかく、このアプローチでは、レコードを見つけるのに約30マイクロ秒かかりますが、同じ結果を達成するためのより良い方法はありますか?

更新:将来の参考のために、提案されているようにTDictionaryを使用する新しい実装をここに記述します(Delphi 2009以降で動作します)

procedure PopulateStringList;
begin  
  EnglishDictionary := TDictionary<String, String>.Create;
  EnglishDictionary.Add('CAN_T_FIND_FILE','It is not possible to find the file');
  EnglishDictionary.Add('DUMMY','Just a dummy record');
  // total of 2000 record appended in the same way
end;


function GetTranslation(ResStr:String):String;
var
  ValueFound: Boolean;
begin
  ValueFound:=  EnglishDictionary.TryGetValue(ResStr, Result);
  if not ValueFound then Result := Result + '(Trans N/A)';
end;

新しいGetTranslation関数は、最初のバージョンよりも1000倍高速に実行されます(私の2000サンプルレコードで)。

4

5 に答える 5

18

THashedStringListもっと良いはずだと思います。

于 2010-09-14T14:28:11.953 に答える
15

Delphi 2009 以降では、Generics.Collections で TDictionary< string,string > を使用します。また、 http://dxgettext.po.dk/など、アプリケーションを翻訳するための無料ツールがあることにも注意してください。

于 2010-09-14T17:30:05.373 に答える
14

THashedStringList が機能する場合、それは素晴らしいことです。その最大の弱点は、リストの内容を変更するたびにハッシュ テーブルが再構築されることです。したがって、リストが小さいままであるか、頻繁に変更されない限り、これは機能します。

これに関する詳細については、THashedStringList の脆弱性を参照してください。いくつかの代替手段が示されています。

更新される可能性のある大きなリストがある場合は、変更のたびにテーブル全体を再計算する必要がない gabr でGpStringHash試してみてください。

于 2010-09-14T16:06:00.643 に答える
4

EnglishStringList(TStringList) を正しく使用していないと思います。これはソートされたリストです。要素 (文字列) を追加してソートしますが、検索するときは、部分的な文字列 (名前のみ、IndexOfNameを使用) でこれを行います。

ソートされたリストでIndexOfNameを使用する場合、 TStringListは二分法検索を使用できません。順次検索を使用します。

(これは IndexOfName の実装です)

  for Result := 0 to GetCount - 1 do
  begin
    S := Get(Result);
    P := AnsiPos('=', S);
    if (P <> 0) and (CompareStrings(Copy(S, 1, P - 1), Name) = 0) then Exit;
  end;

これがパフォーマンスの低下の原因だと思います。
代替手段は 2 TStringList を使用します。
* 最初の (ソートされた) には、「名前」と、値を含む 2 番目のリストへのポインタのみが含まれます。Object プロパティの「ポインタ」を使用して、2 番目のリストへのこのポインタを実装できます。
* 2 番目の (ソートされていない) リストには、値が含まれています。

検索するときは、最初のリストで行います。この場合、Findメソッドを使用できます。名前が見つかると、ポインター (Object プロパティで実装) が 2 番目のリストの位置を値とともに示します。

この場合、Sorted List の Find メソッドは、HashList (値の位置を取得するために関数を実行する必要があります) よりも効率的です。

よろしく。

Pd:英語の間違いですみません。

于 2010-09-14T16:18:13.423 に答える
2

CLASS HELPERを使用して、「IndexOfName」関数を再プログラムすることもできます。

TYPE
  TStringsHelper = CLASS HELPER FOR TStrings
                     FUNCTION IndexOfName(CONST Name : STRING) : INTEGER;
                   END;

FUNCTION TStringsHelper.IndexOfName(CONST Name : STRING) : INTEGER;
  VAR
    SL  : TStringList ABSOLUTE Self;
    S,T : STRING;
    I   : INTEGER;

  BEGIN
    IF (Self IS TStringList) AND SL.Sorted THEN BEGIN
      S:=Name+NameValueSeparator;
      IF SL.Find(S,I) THEN
        Result:=I
      ELSE IF (I<0) OR (I>=Count) THEN
        Result:=-1
      ELSE BEGIN
        T:=SL[I];
        IF CompareStrings(COPY(T,1,LENGTH(S)),S)=0 THEN Result:=I ELSE Result:=-1
      END;
      EXIT
    END;
    Result:=INHERITED IndexOfName(Name)
  END;

(または、クラスヘルパーが気に入らない場合、またはDelphiバージョンにクラスヘルパーがない場合は、子孫のTStringsクラスに実装します)。

これは、ソートされたTStringListでのバイナリ検索と、他のTStringsクラスでのシーケンシャル検索を使用します。

于 2010-10-08T12:48:31.050 に答える