Kurz6 - Kapitola9

17. června 2007 v 10:37 | http://www.sweb.cz/kurz_evt/ |  Programování pro WinCE

8.9 Řazení podle abecedy

I když dokážete vkládat jména s těmi nejkrkolomnějšími nabodeníčky, čeština v programu stále zlobí. Asi jste si všimli, že všechna malá písmena a jména začínající znakem s čárkou nebo háčkem spolehlivě řadí na poslední kartu. Při kontrole Windows 1250 kódové tabulky je to všechno v pořádku. Malá písmena a znaky s diakritikou jsou v tabulce opravdu ke konci.
SQLite je kvalitní databáze, bohužel nepočítá s jinými jazyky než je angličtina. SQL příkaz SELECT, který má zahrnutou standardní klauzuli ORDER BY, třídí standardně podle anglické abecedy.
Aby bylo možné pracovat i v jiných jazycích (nebo řadit podle speciálního kritéria), je možné v SQLite zaregistrovat uživatelskou třídící funkci. Tato funkce má předepsaný přesný tvar. Doplňme tedy do programu novou funkci
// Tabulka poradi ceskych znaku v ceske abecede pro Win1250
static char tab[] =
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // nonprintable
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // nonprintable
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //!"#$%&'()*+,-./
1,2,3,4,5,6,7,8,9,10,0,0,0,0,0,0, //0123456789:;<=>?
0,11,15,17,21,25,31,33,35,37,41,43,45,47,49,53, //@ABCDEFGHIJKLMNO
57,59,61,65,69,73,79,81,83,85,89,0,0,0,0,0, //PQRSTUVWXYZ[\]^_
0,13,16,18,22,28,32,34,36,39,42,44,46,48,50,55, //`abcdefghijklmno
58,60,62,66,70,76,80,82,84,87,90,0,0,0,0,0, //pqrstuvwxyz{|}~
0,0,0,0,0,0,0,0,0,0,67,0,0,71,91,0, //€�'�"…†‡�‰Š‹ŚŤŽŹ
0,0,0,0,0,0,0,0,0,0,68,0,0,72,92,0, //�''""•--�™š›śťžź
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //°±˛ł´µ¶·¸ąş»Ľ˝ľż
0,12,0,0,0,0,0,0,19,26,0,0,27,38,0,23, //ŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎ
0,0,51,54,0,0,0,0,63,75,74,0,0,86,0,0, //ĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢß
0,14,0,0,0,0,0,0,20,29,0,0,30,40,0,24, //ŕáâăäĺćçčéęëěíîď
0,0,52,56,0,0,0,0,64,78,77,0,0,88,0,0 //đńňóôőö÷řůúűüýţ˙
};

int mySQLiteColl(void* NotUsed, int delka1, const void* str1, int delka2, const void* str2)
{
int kolik;
char *ch1, *ch2;

// Pouziju pomocne ukazatele na retezech pro pretypovani (slo by pretypovat primo pri volani tabulky)
ch1=(char*) str1; ch2=(char*) str2;
// Porovnavam znaky retezce maximalne pouze pro pocet znaku kratsiho retezce
kolik=(delka1<delka2) ? delka1 : delka2;
// Pokud na nektere pozici narazim na odchylku, vratim ji jako vystupni hodnotu
for(int i=0; i<kolik; i++)
// Pro spravnou funkci pouziju omezeni indexu tabulky na 8 bitu (aby prekladac nepridaval "1" u zapornych cisel)
if(tab[ch1[i] & 0x0FF]-tab[ch2[i] & 0x0FF]) return (int)(tab[ch1[i] & 0x0FF]-tab[ch2[i] & 0x0FF]);
// Na cele porovnavane delce jsou retezce shodne, jeste muze rozhodnout jejich delka
return delka1-delka2;
}
Současně můžeme doplnit i funkci, která bude užitečná při vybírání položek pro jednotlivé záložky. Tuto funkci zapojíme do klauzule WHERE, kde nahradí porovnávání "<" a ">". Pro uživatelskou funkci existují opět přesná pravidla a tvar.
Já jsem vytvořil následující funkci:
void PageCZ(sqlite3_context *ct,int nparam, sqlite3_value **valarr)
{
const unsigned char * surn;
int iPrvZnak, iPocZnaku;

// Do pomocne promenne si prenesu ukazatel na testovane jmeno
surn = sqlite3_value_text(valarr[0]);
// Do prvni promenne si prenesu poradove cislo prvniho povoleneho znaku
iPrvZnak = sqlite3_value_int(valarr[1]);
// Do dalsi promenne si vlozim, kolik znaku zahrnuje dana zalozka
iPocZnaku = sqlite3_value_int(valarr[2]);
// Test, zda je prvni pismeno v tolerancnim pasmu
if((tab[surn[0] & 0x0FF] >= iPrvZnak) && (tab[surn[0] & 0x0FF] < (iPrvZnak+iPocZnaku)))
{
sqlite3_result_int(ct,1);
return;
}
// Nevlezlo se do tolerance - vracim "neshodu"
sqlite3_result_int(ct,0);
}
První parametr musíme předat do funkce sqlite3_result_int, pomocí níž vracíme hodnotu. Protože budeme mít 3 parametry (první je textový řetězec, druhý a třetí číslo int) můžeme si je přímo vybrat z pole parametrů pomocí sqlite3_value_text, resp. sqlite3_value_int. Pro bližší prozkoumání můžete zabrousit na stránky SQLite a prostudovat dokumentaci.
Nachystané funkce již můžeme zapojit do práce. Upravte část funkce FillListView:
   .
.
.
// Podle prepnute karty nachystam prikaz SELECT pro vyber z databaze
pom=(_T("SELECT * FROM TelNumbers WHERE "));
switch(m_karta) {
case 0: pom+=(_T("PAGECZ(Surname,0,21)")); break;
case 1: pom+=(_T("PAGECZ(Surname,21,12)")); break;
case 2: pom+=(_T("PAGECZ(Surname,33,8)")); break;
case 3: pom+=(_T("PAGECZ(Surname,41,6)")); break;
case 4: pom+=(_T("PAGECZ(Surname,47,10)")); break;
case 5: pom+=(_T("PAGECZ(Surname,57,12)")); break;
case 6: pom+=(_T("PAGECZ(Surname,69,14)")); break;
case 7: pom+=(_T("PAGECZ(Surname,83,100)")); break;
}
// Z databaze vyberu prislusne polozky
switch (m_kategorie) {
case 1: pom+=_T(" AND Category = 1 ORDER BY Surname COLLATE MyColl"); break;
case 2: pom+=_T(" AND Category = 2 ORDER BY Surname COLLATE MyColl"); break;
case 3: pom+=_T(" AND Category > 0 ORDER BY Surname COLLATE MyColl"); break;
default: pom+=_T(" AND Category = 0 ORDER BY Surname COLLATE MyColl");
}

if(dbFile.Open(_T("TelNumbs.tnb"),CFile::modeRead)) {
dbFile.Close();
// Databaze existuje, muzu s ni pracovat
rc = sqlite3_open("TelNumbs.tnb", &db);
if( rc ){
MessageBox(_T("Can't open database:"));
sqlite3_close(db);
exit(1);
}
// Zkusit nastavit novou porovnavaci funkci
rc = sqlite3_create_collation(db, "myColl", SQLITE_UTF8, NULL, mySQLiteColl);
if( rc ){
MessageBox(_T("Error collate function"));
sqlite3_free(zErrMsg);
}
// Zkusit nastavit novou funkci pro vyber jmena podle znaku
rc = sqlite3_create_function(db, "PAGECZ", 3, SQLITE_UTF8, NULL, PageCZ, NULL, NULL);
if( rc ){
MessageBox(_T("Error page select function"));
sqlite3_free(zErrMsg);
}
// Vyjmu z databaze recordset s polozkami ...
rc = sqlite3_exec(db, CharStrCZ(pom), callback, pView, &zErrMsg);
if( rc!=SQLITE_OK ){
MessageBox(_T("SQL SELECT Error!"));
sqlite3_free(zErrMsg);
}
}
.
.
.
Vyzkoušejte co nejdivočejší česká jména a otestujte funkci programu. Pro slovenské čtenáře stačí opět upravit tabulku pořadí znaků.

Co bychom si měli z této lekce zapamatovat?

  • I když SQLite nepracuje s češtinou, můžeme si potřebné funkce doplnit.
 

Buď první, kdo ohodnotí tento článek.

Nový komentář

Přihlásit se
  Ještě nemáte vlastní web? Můžete si jej zdarma založit na Blog.cz.