Problémy s TStringList

vložil Radek Červinka 17. dubna 2012 23:35

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.

Tagy: ,

Praxe

Komentáře

18.4.2012 10:36:12 #

Zdeněk Vašků

Jelikož se jedná o UTF, nemohlo by to být s pojenoé s normalizací s porovnávání textů?

Zdeněk Vašků

18.4.2012 11:36:18 #

JaroB

No, já měl kdysi kapku potíž s nějakou verzí Soundexu, jednalo se o chybnou implementaci části jazykového korpusu; slova, která byla jinak zapsaná tak se chovala jako stejná.

JaroB

Komentování ukončeno

Naše nabídka

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Poslední komentáře

Comment RSS

Dle měsíců