Přišel mi mail od čtenáře Jiří Milička a zkusím ho zde publikovat - třeba to někomu pomůže.
Ve zkratce tvrdí, že přišel na dvě chyby s TStringList:
procedure Přiřaď;
var
Text, Slovník: TStringList;
Slovo: String;
Pozice: Int32;
begin
Text:=TStringList.Create;
Text.LoadFromFile('text.txt', TEncoding.utf8);
Slovník:=TStringList.Create;
Slovník.Sorted:=true;
Slovník.Duplicates:=dupIgnore;
Slovník.AddStrings(Text); // Vytváření slovníku
for Slovo in Text do // Mapování slov na pořadí ve slovníku
if Slovník.Find(Slovo, Pozice) then
begin
if slovník[Pozice] <> Slovo then
begin
ShowMessage('Chyba 1: Slovo není tam, kde jsem ho našel.');
end
else
ShowMessage('Chyba 2: Slovo ve slovníku jsem nenašel, přestože tam je.');
end;
Text.Free;
Slovník.Free
end;
Kód zkompilujete a spustíte na Win XP. Vše funguje, slunce svítí, tráva je zelená. Pak totéž přenesete na Win 7 a při zpracování většího množství textu v různých jazycích se nestačíte divit. Chyba 1 se ozve ve chvíli, kdy na vstupu bude slovo skládající se z jednoho znaku s hodnotou mezi $2000 až $200F. Chyba 2 se ozve při práci například s arabštinou. Tedy popravdě, ty chybové hlášky jsem tam původně neměl. Prostě mě trestuhodně nenapadlo, že by se něco takového vůbec mohlo stát.
Funkce TStringList.Sort totiž volá funkci Win API CompareString , která porovnává řetězce podle místního nastavení. TStringList.Find by měl volat úplně stejnou fci, ale evidentně je něco špatně. Mohlo by to jít řešit přes TStringList.CustomSort? Možná ano, ale po dvou hodinách jsem ztratil nervy a… vytvořil miliontou prvou implementaci quicksortu a binárního vyhledávání. Příběh má pointu. Běží to rychleji. A slovník se na libovolných Win vytvoří stejným způsobem, což občas taky není k zahození.
Napsal jsem mu, ať pro zajímavost zkusí TWideStringList ze System.WideStrings.
Odpověď: TWideStringList se chová v tomto případě stejně jako TStringList.
Už jsem sice celou věc považoval za uzavřenou (tím, že mám vlastní sort a find, o kterém vím, co přesně dělají), ale když jsem se díval na ten TWideStringList, tak mě zaujala ještě jedna věc: chyba číslo 1 totiž nastává i na Win XP a to v dost překvapivých souvislostech. Při zpracovávání arabského textu se totiž třídicí a vyhledávací algoritmy z nějakého důvodu řídí jakoby fonologickou a ne grafickou hodnotou. Například slovo نظرت fce find považuje za stejné jako slovo نظرة (nevím, jak se ti to zobrazilo, ale asi je vidět, že to graficky nejsou stejná slova, mají jinou příponu) - a ona se dost často skutečně čtou stejně! (Ale nečtou se tak vždycky a prostě jsou to jiná slova, takže je to chyba).
A podobně to špatně nachází i jiná slova se stejnou příponou. Jestli je to záměr, tak jim to muselo dát spoustu práce a přitom je to k dost k ničemu, jestli je to bug, tak je to dost divná náhoda… Stejný problém je i na Win7.
V Delphi 6 je vše bez problémů, ať pro UTF8 tak pro jednobytové kódování, na obou systémech. Jenom se musí dávat pozor na slovnik.CaseSensitive, které je defaultně nastavené na false.
Já: Proč nepoužiješ generika, resp. TDictionary?
Jiří Milička napsal(a):
K hashům - příklad jsem zjednodušil, celé je to trochu složitější, ale pravda je, že by šlo použít dvakrát TDictionary - potřebuju totiž rychlý přístup ze směru key i value. Asi bych měl specifikovat, k čemu to vlastně celé je. Když je databáze hotová, tak hledání v ní vypadá následovně:
- 1) ve slovníku se pomocí bin search vyhledá slovo, které zadá uživatel
- 2) pozice toho slova určuje řádek v indexu, podle kterého se vyhledají pozice tohoto slova v "textu", který je z určitých důvodů převedený na čísla, která znamenají pozici ve slovníku.
- 3) okolí dejme tomu +-10 čísel se "přeloží" zpátky na stringy a odešlou k uživateli.
Asi máš pravdu, že TString list už dneska nemá pro tohle moc smysl používat. Ale stejně mě vždycky trochu rozladí, když staré věci, které už mám ověřené, najednou přestanou fungovat. Třeba FireMonkey naopak odpustím ledasjaký bug, prostě je to nová technologie a tak s tím počítám dopředu…
Závěr: No je to zajímavé, první chyba je evidentně bug - druhá nevím. Požádal jsem autora o zavedení do QC - uvidíme. Ještě že neumím arabsky.