Slovenčina a triedenie znakov v UTF8

Ako sú zotriedené slovenské znaky v znakovej sade ut8 a prečo databázy nesprávne zobrazujú výsledky dopytov.
Zaujali sme Vás?
Zobraziť kontaktné údaje

Nedávno som pri tvorbe databázy miest a obcí, narazil na celkom zaujímavý problém so znakovou sadou. Na prvý pohľad je to veľmi jednoduché zadanie a väčšina programátorov si povie, že navrhnúť štruktúru databázy je práca na niekoľko minút.

Keďže išlo o české a slovenské mestá, ako zotriedenie pre databázu, tabuľky a stĺpce som zvolil utf8_slovak_ci. Názvy miest som importoval z rôznych zdrojov.

 

CREATE TABLE IF NOT EXISTS `tblCities` (
`id` int(11) NOT AUTO_INCREMENT,
`district_id` int(11) NOT ,
`title` varchar(50) COLLATE utf8_slovak_ci NOT ,
PRIMARY KEY (`id`),
KEY `district_id` (`district_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci AUTO_INCREMENT=1 ;

Spustil som import zo súborov a dáta som mal po niekoľkých sekundách v databáze.

Problém nastal až keď som databázu začal používať. Myslím, že každý z nás pozná slovenskú abecedu a ak si ju z 1. ročníka na základnej škole nepamätá, tak pre osvieženie:

a, á, ä, b, c, č, d, ď, dz, dž, e, é, f, g, h, ch, i, í, j, k, l, ĺ, ľ, m, n, ň, o, ó, ô, p, q, r, ŕ, s, š, t, ť, u, ú, v, w, x, y, ý, z, ž

http://sk.wikipedia.org/wiki/Slovenská_abeceda

Prečo som uviedol abecedu? Keď som podľa nej dal zotriediť všetky mestá v databáze pomocou dopytu:

SELECT * FROM `tblCities` ORDER BY `tblCities`.`title` ASC;

Zobrazil sa mi nasledovný výsledok:

id   | district_id   | title
-----+---------------+--------
1 | 6 | Ábelová
2 | 87 | Abertamy
3 | 9 | Cabov
4 | 55 | Čabalovce

Po prekontrolovaní aplikácie som sa pustil do hľadania v internete. Dopracoval som sa až k definícii znakovej sady, ktorú síce implementuje MySQL 6, ale chyba nie je odstránená.

http://www.collation-charts.org/mysql60/mysql604.utf8_slovak_ci.html

Podľa tabuľky sú z nejakého dôvodu akýmsi spôsobom zjednotené niektoré písmená. Neviem prísť na princíp, podľa ktorého sa zjednocovali. Možno by nám to vedel vysvetliť niekto, kto sa venuje gramatológii. Bohužial nikoho takého nepoznám a ani som nenašiel. Hovorím napríklad o písmenách „č“, „ď“, „ň“, ...
Zatiaľ čo spoluhlásky „c“ a „č“ sú oddelné a zotriedenie naozaj funguje správne, zvyšné spoluhlásky a takmer všetky samohlásky sú zjednotené. V praxi to znamená, že ak v dopyte uvediete napríklad písmeno „a“ alebo „á“, písmeno sa stále považuje za „a“ a podľa toho sa vám zobrazí výsledok.

SELECT * FROM `tblCities` WHERE `title` LIKE 'abe%'; Chyba – vráti 2 záznamy
SELECT * FROM `tblCities` WHERE `title` LIKE 'ábe%'; Chyba – vráti 2 záznamy
SELECT * FROM `tblCities` WHERE `title` LIKE 'cab%'; Správne – vráti 1 záznam
SELECT * FROM `tblCities` WHERE `title` LIKE 'čab%'; Správne – vráti 1 záznam

Kvôli tomuto pravidlu teda nefunguje správne ani zotriedenie (ORDER BY).

Na stránkach MySQL som našiel dvoch slovákov, ktori na túto chybu upozorňovali pred niekoľkými rokmi. Keďže MySQL priamo nezodpovedá za tvorbu znakovej sady, ich odpoveď bola, že to majú implementované správne a nič s tým nespravia, hľadal som ďalej.

Tvorcovia operačných systémov, databázových systémov a ďalší, používaju znakovú sadu definovanú organizáciou The Unicode Consortium (http://unicode.org/). Pred niekoľkými dňami (16.11.2012) vydali nový release jadra Unicode, v ktorom som našiel aj xml špecifikáciu pre slovenčinu. Problém v ňom stále pretrváva. Hľadal som na ich stránke, či už túto chybu niekto s nimi riešil, no nič také nemajú zverejnené. Preto som zaslal ich adresu podrobný popis tohto problému a čakám na ich odpoveď.

Keďže je riešenie tohto problému zatiaľ v nedohľadne, musím sa spoľahnúť na programovanie a dáta si pred zobrazením preusporiadať manuálne (späť k latin1_swedish_ci :-)).

Diskusia ku článku
  Pridať komentár
Milsa
22.03.2013, 01:34
cs.wikipedia.org/wiki/Abecední_řazení#.C4.8Ce.C5.A1tina
Toto sa týka češtiny. Znaky, ktorých význam môže zmeniť nasledujúce písmeno (d, t, n, l) a samohlasky majú rovnakú hodnotu bez ohľadu na diakritiku. Dúfam, že som pomohol. Ak som napísal v prvom príspevku iný email, tak som sa pomýlil. Správny je v tomto.   Reagovať
Ondrej Balko
22.03.2013, 09:41
Asi máte na mysli túto vetu: "Nejprve se řadí znaky bez diakritických znamének, po nich následují znaky s čárkou, po nich znaky s háčkem (kromě případů, kdy má primární řadicí platnost), po nich znaky s kroužkem." Ak by to fungovalo takto, tak by to bolo v poriadku. V skutočnosti je databázovým systémom úplne jedno či sa slová zhodujú v znakoch s diakritikou, jednoducho ich zoradí ako keby boli všetky bez diakritiky.   Reagovať
Milsa
22.03.2013, 23:41
Ignorovať diakritiku by mal utf8-general-ci. utf8-slovak-ci by mal ignorovať diakritiku len u vybraných písmen ako, napr., D, ale nie, napr., C. V blízkej dobe si to otestujem.   Reagovať
Ondrej Balko
23.03.2013, 11:14
Nerozumiem o čo vám ide pan Šabík, píšem článok o tom ako sú ignorované niektoré písmená s diakritikou a Vy mi vravíte, že to čo píšem nie je pravda a sú ignorované iba niektoré písmená s diakritikou.
Toto nie je vôbec ten správny spôsob ako na seba upozorňovať.   Reagovať
Milsa
22.03.2013, 01:21
Je to správne. Nájdite si na internete normu o triedení znakov v slovenčine.   Reagovať