[英]How can I search faster for name/value pairs in a Delphi TStringList?
我通过在运行时将所有字符串放在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个样本记录上)。
我想, THashedStringList
应该更好。
在Delphi 2009或更高版本中,我将在Generics.Collections中使用TDictionary <string,string>。 另请注意,有一些免费工具,如http://dxgettext.po.dk/,用于翻译应用程序。
如果THashedStringList适合你,那很好。 它最大的缺点是每次更改列表的内容时,都会重建哈希表。 因此,只要您的列表仍然很小或者不经常更改,它就会对您有用。
有关这方面的更多信息,请参阅: THashedStringList弱点 ,它提供了一些替代方案。
如果您有可能会被更新的大名单,你可能想尝试GpStringHash由贾布尔 ,即不必在每次改变重新计算整个表。
我认为你没有正确使用EnglishStringList(TStringList)。 这是一个排序列表,您添加元素(字符串),然后对其进行排序,但在搜索时,您可以通过部分字符串(仅使用IndexOfName的名称)来执行此操作。
如果在排序列表中使用IndexOfName ,则TStringList不能使用Dicotomic搜索。 它使用顺序搜索。
(这是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:
*第一个(已排序)仅包含“名称”和指向包含该值的第二个列表的指针; 您可以使用Object属性的“指针”将此指针实现到第二个列表。
*第二个(未排序的)列表包含值。
搜索时,您可以在第一个列表中进行搜索; 在这种情况下,您可以使用Find方法。 当您找到名称时,指针(使用Object属性实现)会在第二个列表中为您提供值。
在这种情况下,Sorted List上的Find方法比HashList(必须执行一个函数来获取值的位置)更有效。
问候。
钯:请原谅我的英语错误。
您还可以使用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;
(或者如果您不喜欢CLASS HELPERs或者在Delphi版本中没有它们,则在TStrings后代类中实现它)。
这将在已排序的TStringList上使用二进制搜索,在其他TStrings类上使用顺序搜索。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.