Kuidas Linuxi sort funktsioon sorteerib ridu

Sissejuhatus

KĂ”ik algas lĂŒhikesest skriptist, mis pidi ĂŒhendama teavet aadresside e-mail töötajatest, mis saadud meililisti kasutajate loendist, koos töötajate ametikohtadega, mis saadud personaliosakonna andmebaasist. MĂ”lemad loendid eksportiti tekstifailidena Unicode'i kodeeringus UTF-8 ja salvestati unixi lĂ”ppudega.

Sisu mail.txt

Ivanov Andre;ia@example.com

Sisu buhg.txt

Ivanova Alla;maaler
Jolkin Ella;kraanajuht
Ivanov Andre;torumees
Abakanov Mihail;maaler

Failide ĂŒhendamiseks sortsiti failid unixi kĂ€su abil sort ja edastati unixi programmile join, mis lĂ”petas ootamatult tĂ”rke tĂ”ttu:

$> sort buhg.txt > buhg.srt
$> sort mail.txt > mail.srt
$> join buhg.srt mail.srt > result
join: buhg.srt:4: pole sorteeritud: Ivanov Andre;torumees

Sorteerimise tulemus nÀgi silmaga vaadates vÀlja Ôige, kuid meeste ja naiste perekonnanimede kokkulangemisel on naised enne mehi:

$> sort buhg.txt
Abakanov Mihail;maaler
Jolkin Ella;kraanajuht
Ivanova Alla;maaler
Ivanov Andre;torumees

Tundub, et see on unicode'i sortimise viga vÔi naiste Ôiguste manifestatsioon sortimise algoritmis. Esimene tundub muidugi usutavam.

JĂ€tame hetkel kĂ”rvale join ja keskendume sort. Proovime lahendada ĂŒlesande teadlikult eksitades. Alustuseks muudame lokaali en_US . Tundub, et ru_RU. Sorteerimiseks piisaks keskkonnamuutuja seadmisest LC_COLLATE, aga me ei hakka pisiasju ajama:

$> LANG=ru_RU.UTF-8 sort buhg.txt
Abakanov Mihail;maaler
Jolkin Ella;kraanajuht
Ivanova Alla;maaler
Ivanov Andre;torumees

Miski ei muutunud.

Proovime faile ĂŒhekordse kodeeringusse edastada:

$> iconv -f UTF-8 -t KOI8-R buhg.txt 
 | LANG=ru_RU.KOI8-R sort 
 | iconv -f KOI8-R -t UTF8

Taaskord ei muutunud miski.

Mitte midagi teha, tuleb otsida lahendust internetist. Otse vene perekonnanimede kohta ei ole midagi, kuid on kĂŒsimusi teiste sorteerimise veidrustega. NĂ€iteks selline probleem: unix sort kĂ€sitleb ‘-’ (miinus) mĂ€rke nĂ€htamatutena. Kui lĂŒhidalt, siis stringid "a-b", "aa", "ac" sorteeritakse kui "aa", "a-b", "ac".

Vastus on kÔikjal standardne: kasutage programmeerija lokaali "C" ja teil on Ônne. Proovime:

$> LANG=C sort buhg.txt
Jolkin Ella;kraanajuht
Abakanov Mihail;maaler
Ivanov Andre;torumees
Ivanova Alla;advokaat

Midagi on muutunud. Ivanovid on Ă”iges jĂ€rjekorras, tĂ”epoolest on Jolkin kuhugi kadunud. Naaseme algse ĂŒlesande juurde:

$> LANG=C sort buhg.txt > buhg.srt
$> LANG=C sort mail.txt > mail.srt
$> LANG=C join buhg.srt mail.srt > result

See toimis ilma vigadeta, nagu lubas internet. Ja see kÔik vaatamata Ёlkina esimeses reas.

Probleem nĂ€ib olevat lahendatud, kuid igaks juhuks proovime veel ĂŒhte vene kodeeringut — Windowsi kodeeringut CP1251:

$> iconv -f UTF-8 -t CP1251 buhg.txt 
 | LANG=ru_RU.CP1251 sort 
 | iconv -f CP1251 -t UTF8 

Sorteerimise tulemus, ootamatult, vastab lokaalile "C", ja kogu nĂ€ide, vastavalt, lĂ€bib veatut. Miski mĂŒstiline.

Ma ei armasta mĂŒstikat programmeerimises, kuna tavaliselt varjab see vigu. Pean tĂ”siselt tegelema kĂŒsimusega, kuidas see töötab sort ja millele see mĂ”jutab LC_COLLATE .

LĂ”pus pĂŒĂŒan vastata kĂŒsimustele:

  • miks naiste perekonnanimesid sorteeriti valesti
  • miks LANG=ru_RU.CP1251 osutus ekvivalentseks LANG=C
  • miks on sort ja join erinevad arusaamad sorteeritud ridade jĂ€rjestusest
  • miks on kĂ”igis minu nĂ€idetes vead
  • lĂ”puks, kuidas sorteerida ridu oma maitse jĂ€rgi

Sorteerimine UTF-8 formaadis

Esimene peatus on tehniline aruanne nr 10 pealkirjaga Unicode collation algorithm veebisaidil unicode.org. Aruanne sisaldab palju tehnilisi detaile, nii et luban endale tuua lĂŒhikese ĂŒlevaate pĂ”hiteesidest.

VĂ”rdlemine — "vĂ”rdlus" ridade vahel — on iga sorteerimisalgoritmi aluseks. Igal algoritmil vĂ”ivad olla erinevused ("mull", "ĂŒhendamine", "kiire"), kuid kĂ”ik need kasutavad ridade paaride vĂ”rdlemist, et mÀÀrata nende jĂ€rjestus.

Ridade sorteerimine loomulikus keeles on ĂŒsna keeruline probleem. Isegi kĂ”ige lihtsamates ĂŒhebaidistes kodeeringutes ei vasta tĂ€htede jĂ€rjekord tĂ€hestikus, mis on mingil mÀÀral erinev ingliskeelsest, juba numbrilistele vÀÀrtustele, millega need tĂ€hed kodeeritakse. Nii on saksa tĂ€hestikus tĂ€ht Ö paikneb kui O ja P, ja kodeeringus CP850 sattub see vahele Ăż ja Ü.

Saame proovida abstraktiseerida konkreetse kodeeringu ja vaadata "ideaalseid" tĂ€hti, mis asuvad mingis jĂ€rjestuses, nagu see on tehtud UTF-8. Kodeeringud UTF8, UTF16 vĂ”i ĂŒhebaidine KOI8-R (kui on vaja piiratud alamsĂŒsteemi UTF-8-st) annavad erinevad numbrilised esitlused tĂ€htedele, kuid viitavad samadele elementidele pĂ”hitaabelis.

Selgub, et isegi nullist sĂŒmbolite tabeli koostamine ei vĂ”imalda meil mÀÀrata universaalset sĂŒmbolite jĂ€rjekorda. Erinevates rahvuslikes tĂ€hestikes, mis kasutavad samu tĂ€hti, vĂ”ib nende tĂ€htede jĂ€rjekord erineda. NĂ€iteks prantsuse keeles Æ loetakse ligatuuriks ja sorteeritakse nagu string AE. Norra keeles Æ loetakse eraldi tĂ€hiseks, mis asub pĂ€rast Z. Muide, lisaks ligatuuride tĂŒĂŒpidele Æ on olemas ka tĂ€hed, mis on kirjutatud mitme sĂŒmboliga. Tshehhi tĂ€hestikus on tĂ€ht Ch, mis asub kahe vahel H ja I.

Lisaks tĂ€hestike erinevusele on olemas ka muid rahvuslikke traditsioone, mis mĂ”jutavad sortimist. EelkĂ”ige tekib kĂŒsimus: millises jĂ€rjekorras peaksid sĂ”naraamatus olema sĂ”nad, mis koosnevad suurtest ja vĂ€ikestest tĂ€htedest? Samuti vĂ”ivad sortimist mĂ”jutada kirjavahemĂ€rgi kasutamise eripĂ€rad. Hispaania keeles asetatakse kĂŒsimuse ette pööratud kĂŒsimĂ€rk (ÂżTe gusta la mĂșsica?). Sel juhul on selge, et kĂŒsimused ei tohiks rĂŒhmituda eraldi klastrisse vĂ€ljaspool tĂ€hestikku, vaid kuidas sorteerida stringe koos teiste kirjavahemĂ€rkidega?

Ma ei hakka peatuma stringide sortimisel keeltes, mis oluliselt erinevad Euroopa keeltest. Tahan mĂ€rkida, et keeltes, kus kirjutamise suund on paremalt vasakule vĂ”i ĂŒlalti alla, hoitakse tĂ”enĂ€oliselt stringide sĂŒmboleid lugemise jĂ€rjekorras ning isegi mitte-tĂ€hestikulistes kirjutistes on oma meetodid stringide sĂŒmbolite jĂ€rjekorda seadmiseks. NĂ€iteks vĂ”ivad hieroglĂŒĂŒfid olla jĂ€rjestatud nende joonistuse jĂ€rgi (hiina hieroglĂŒĂŒfide vĂ”tmed) vĂ”i hÀÀlduse jĂ€rgi. Kuidas peaksid emoji sorteerima, ei oska ma ausalt öelda, kuid ka nende jaoks saab midagi vĂ€lja mĂ”elda.

Tulenevalt eespool mainitud omadustest on vÀlja töötatud peamised nÔuded stringide vÔrdlemiseks, mis pÔhinevad Unicode tabelitel:

  • stringide vĂ”rdlemine ei sĂ”ltu sĂŒmbolite asukohast kooditabelis;
  • sĂŒmbolite jĂ€rjestused, mis moodustavad ĂŒhe sĂŒmboli, viiakse kanonilisse vormi (A + ĂŒlemine ring on sama, mis Å);
  • stringide vĂ”rdlemisel kĂ€sitletakse sĂŒmbolit kontekstis ja vajadusel ĂŒhendatakse see naabritega ĂŒhe vĂ”rdlusĂŒksusena (Ch tshehhi keeles) vĂ”i jagatakse mitmeks (Æ prantsuse keeles);
  • kĂ”ik rahvuslikud omadused (alfabeet, suur/kirjas, kirjavahemĂ€rgid, kirjutamisviiside jĂ€rjekord) peavad olema seadistatavad kuni kĂ€sitsi mÀÀramiseni (emodĆŸid);
  • vĂ”rdlemine on oluline mitte ainult sortimise jaoks, vaid ka paljude muude kohtade jaoks, nĂ€iteks ridade vahemike mÀÀramisel (asendus {A
 я} sisse bash);
  • vĂ”rdlemine peab toimuma piisavalt kiiresti.

Lisaks on raporti autorid formuleerinud vÔrdlemise omadused, millele algoritmi arendajad ei peaks toetuma:

  • vĂ”rdlemise algoritm ei tohi nĂ”uda iga keele jaoks eraldi sĂŒmbolite komplekti (vene ja ukraina keel kasutavad enamikku kirillitsast ĂŒhiselt);
  • vĂ”rdlemine ei tohi toetuda sĂŒmbolite jĂ€rjekorrale Unicode tabelites;
  • stringi kaal ei tohi olla stringi atribuut, kuna sama string erinevates kultuurilistes kontekstides vĂ”ib omada erinevaid kaalu;
  • stringide kaalud vĂ”ivad muutuda liitmise vĂ”i jagamise kĂ€igus (vĂ€lja x < y ei tĂ€henda, et xz < yz);
  • erinevad stringid, millel on samad kaalud, loetakse sortimisalgoritmi seisukohalt vĂ”rdseks. Selliste stringide tĂ€iendava jĂ€rjekorda seadmise vĂ”imalus on olemas, kuid see vĂ”ib halvendada jĂ”udlust;
  • korrastatud sortimisel vĂ”ivad samade kaaludega stringid omavahel vahetuda. Stabiilsus on konkreetse sortimisalgoritmi omadus, mitte stringide vĂ”rdlemise algoritmi omadus (vt eelmist punkti);
  • sortimisreeglid vĂ”ivad aja jooksul muutuda, kui kultuurilised traditsioonid tĂ€ienevad/muudavad.

Samuti on mÀrgitud, et vÔrdlemise algoritm ei tea midagi vÔrreldavate stringide semantikast. Seega ei tohi ainult numbritest koosnevaid stringe vÔrrelda kui arvusid, ja ingliskeelsete nimetuste loendites ei tohi artikkel eemalduda (Beatles, The).

KÀideldes kÔiki nÔutud tingimusi, on ette nÀhtud mitmeastmeline (praktiliselt neljast astmest koosnev) tabelialgoritm.

Eelnevalt viidatakse, et stringi sĂŒmbolid tuuakse kanoniliselt ja rĂŒhmitatakse vĂ”rdlemise ĂŒksusteks. Iga vĂ”rdlemise ĂŒksusele mÀÀratakse mitu kaalu, mis vastavad mitmele vĂ”rdlemise tasemele. VĂ”rdlemise ĂŒksuste kaalud on jĂ€rjestatud hulkade elemendid (antud juhul tĂ€isarvud), mida saab vĂ”rrelda suurem-vĂ€hem. Eriline vÀÀrtus IGNORED (0x0) tĂ€hendab, et vastava vĂ”rdluse tasemel ei osale antud ĂŒksus vĂ”rreldes. Stringide vĂ”rdlemine vĂ”ib korduda mitu korda, kasutades vastavate tasandite kaalu. Igal tasemel vĂ”rreldakse jĂ€rjestikku kahe stringi vĂ”rdlemise kaalude ĂŒksusi.

Erinevates algoritmi rakendustes eri rahvuste traditsioonide jaoks vĂ”ivad tegurite suurused erineda, kuid Unicode'i standardisse kuulub pĂ”hikaalude tabel — "Default Unicode Collation Element Table" (DUCET). Tahan mĂ€rkida, et muutuja seadmine LC_COLLATE on tegelikult viide kaalu tabeli valimisele stringide vĂ”rdlemise funktsioonis.

Kaalu koefitsiendid DUCET on ĂŒles ehitatud jĂ€rgmiselt:

  • esimesel tasemel muudetakse kĂ”ik tĂ€hed ĂŒhte suurust, diakriitilised mĂ€rgid jĂ€etakse vĂ€lja, kirjavahemĂ€rgid (mitte kĂ”ik) ignoreeritakse;
  • teisel tasemel arvestatakse ainult diakriitilisi mĂ€rke;
  • kolmandal tasemel arvestatakse ainult suurust;
  • neljandal tasemel arvestatakse ainult kirjavahemĂ€rke.

VÔrdlemine toimub mitmete lÀbikÀikude kÀigus: esiteks vÔrreldakse esimese taseme koefitsiente; kui kaalud on vÀÀrtustes vÔrdsed, toimub uus vÔrdlemine teise taseme kaaludega; seejÀrel vÔimalikult kolmanda ja neljanda tasemega.

VĂ”rdlemine lĂ”peb, kui stringides on vastavad ĂŒksteisele vĂ”rreldavad ĂŒksused erinevate kaaludega. Stringid, mis omavad vĂ”rdsed kaalu kĂ”igil neljal tasemel, peetakse omavahel vĂ”rdsed.

Just see algoritm (paljude tĂ€iendavate tehniliste detailidega) andis nime aruandele nr 10 — "Unicode Collation Algorithm" (UCA).

Siin muutub sorteerimise kÀitumine meie nÀites mÔnevÔrra selgemaks. Oleks hea seda vÔrrelda Unicode'i standardiga.

Rakenduste testimiseks UCA on olemas spetsiaalne test, mis kasutab kaalude faili, mis rakendab DUCET. Kaalude failis vĂ”ib leida erinevaid huvitavaid asju. NĂ€iteks on seal mahjongi ja Euroopa domino tĂ€ringute jĂ€rjestus ning kaardipakkides mastide jĂ€rjestus (sĂŒmbol 1F000 ja edasi). Kaardimastid on paigutatud vastavalt bridĆŸi reeglitele — PCHBT, ja kaardid mastis — jĂ€rjestuses T, 2, 3
 K.

Stringide sortimise Ă”igsuse kĂ€sitsi kontrollimine vastavalt DUCET oleks ĂŒsna vĂ€sitav, kuid Ă”nneks meie jaoks on olemas silmapaistev teostus Unicode'iga töötamiseks — "Rahvusvahelised komponente Unicode'i jaoks" (ICU).

Selle raamatukogu veebisaidil, mis on vĂ€lja töötatud IBM, on demonstreerimise lehekĂŒljed, sealhulgas stringide vĂ”rdlemise algoritmi leht. Sisestame meie teststringid vaike seadistustega ja, oh imet, saame ideaalse eesti sorteeringu.

Abakanov Mihhail;maalija
Jolkina Ella;kraanaoperaator
Ivanov Andrei;torumees
Ivanova Alla;advokaad

Muide, veebisaidilt ICU leiate tÀpsustusi vÔrdlemise algoritmi toimimise kohta, kui kÀsitletakse kirjavahemÀrke. NÀidetes Collation FAQ ignoreeritakse apostroofe ja sidekriipse.

Unicode aitas meid, kuid peame leidma imelike kÀitumise pÔhjused sort ja Linux kusagil mujal.

Sorteerimine glibc-s

Kiire ĂŒlevaade GNU Core Utilsi sort API-s allikakoodist nĂ€itas, et utiliidi lokaliseerimine piirdub muutujate praeguse vÀÀrtuse vĂ€ljatrĂŒkiga kĂ€ivitamise ajal tĂ”rkeotsingureĆŸiimis: LC_COLLATE $ sort --debug buhg.txt > buhg.srt sort: kasutab ‘en_US.UTF8’ sorteeri reegleid

Stringide vÔrdlemine toimub standardse funktsiooni

strcoll , seega on kĂ”ik huvitav osa raamatukoguststringide vĂ”rdlemisele pĂŒhendatud glibc.

Pealehe wiki projekti glibc ĂŒks lĂ”ik . Sellest lĂ”igust on vĂ”imalik aru saada, etsorteerimine pĂ”hineb juba meile tuntud algoritmil glibc The Unicode collation algorithm UCA () ja/vĂ”i sellele sarnasel standardilISO 14651 Rahvusvaheline stringide jĂ€rjestamise ja vĂ”rdlemise (). Seoses viimase standardiga tuleb mĂ€rkida, et veebisaidilstandards.iso.org on ametlikult kuulutatud avalikuks, kuid vastav link viib mitteeksisteerivale lehele. Google annab mitmeid lehti viidete kohta ametlikele saitidele, mis pakuvad ostmiseks elektroonilist koopiat standardist sajandi euro eest, kuid otsingu kolmandal-neljandal lehel leiate ka otse lingid Rahvusvaheline stringide jĂ€rjestamise ja vĂ”rdlemise . Üldiselt ei erine standard praktiliselt PDF, kuid on igavamat lugeda, kuna ei sisalda eredate nĂ€idete riiklikke omadusi stringide sorteerimisel. UCASellel veebisaidil leidis kĂ”ige huvitavam teave

oli link wiki veakĂŒllastusse stringide vĂ”rdlemise rakenduse arutelu . Arutelust vĂ”ib teada saada, et glibcstringide vĂ”rdlemiseks kasutatakse glibc Common Template Table'i ISOCTT ), mille aadressi leiate standardi (lisast. Aastatel 2000 ja 2015 oli see tabel A tavaliselt stabiilne. Rahvusvaheline stringide jĂ€rjestamise ja vĂ”rdlemise. Aastatel 2000 kuni 2015 ilmus see tabel glibc ei omanud hooldajat ja erines ĂŒsna tugevalt (vĂ€hemalt vĂ€limuselt) praegusest standardi versioonist. Aastatel 2015 kuni 2018 toimus kohandamine uue tabeliversiooniga ja hetkel on teil vĂ”imalus reaalses elus kohtuda nii uue tabeliversiooniga (CentOS 8), kui ka vana (CentOS 7).

NĂŒĂŒd, kui kogu teave algoritmi ja abite tabelite kohta on olemas, saame naasta algse probleemi juurde ja mĂ”ista, kuidas Ă”igesti sorteerida read Vene lokaliseerimise kontekstis.

ISO 14651/14652

Meid huvitava tabeli lÀhtekood lisast enamikes jaotustes Linux asub kataloogis /usr/share/i18n/locales/. Ise tabel asub failis iso14651_t1_common. Siis see fail direktiiviga copy iso14651_t1_common sisaldub failis iso14651_t1, mis omakorda sisaldub riiklikes failides, sealhulgas en_US ja ru_RU. Enamikes jaotustes Linux on kÔik lÀhtefailid osa pÔhinstallatsioonist, kuid kui neid ei ole, tuleb installida tÀiendav paket jaotusest.

Faili struktuur iso14651_t1 vĂ”ib tunduda kohutavalt sĂ”naline, mitte selgete reeglitega nimede koostamisel, kuid kui sĂŒveneda, on kĂ”ik piisavalt lihtne. Struktuur on kirjeldatud standardis ISO 14652, mille koopia on saadaval laadimiseks veebilehelt open-std.org. Veel ĂŒhe faili formaadi kirjeldamise leiate spetsifikatsioonidest POSIX-i alates OpenGroup. Alternatiivina standardi lugemisele vĂ”ite uurida funktsiooni lĂ€htekode collate_read ja glibc/locale/programs/ld-collate.c.

Faili struktuur on jÀrgmine:

Vaikimisi kasutatakse sĂŒmbolit kui ekraanitsĂŒmbolit ja rea lĂ”pp pĂ€rast sĂŒmbolit # on kommentaar. MĂ”lemat sĂŒmbolit saab ĂŒmber mÀÀrata, mis ka toimus uue tabeliversiooniga:

escape_char /
comment_char %

Failis vĂ”ib esineda tokenid formaadis <Uxxxx> vĂ”i <Uxxxxxxxx> kui x — kuusnurkne number). See on Unicode koodpunktide kuusnurkne esituskodeeringus UCS-4 (UTF-32). KĂ”ik muud elemendid nurksulgudes (sealhulgas <Uxxxx_xxxx>, <2> ja sarnased), peetakse lihtsateks stringi konstantideks, millel ei ole eriliselt tĂ€hendust konteksti vĂ€ljaspool.

Rida LC_COLLATE ĂŒtleb meile, et jĂ€rgmised andmed kirjeldavad stringide vĂ”rdlemist.

Esialgu mÀÀratakse kaaludele nimed vĂ”rdlustabelis ja sĂŒmbolite kombinatsioonidele. Üldiselt kuuluvad kaks tĂŒĂŒpi nimesid kahte erinevasse ĂŒksusesse, kuid reaalses failis on need segamini. Kaalude nimed mÀÀratakse vĂ”tmesĂ”naga collating-symbol (vĂ”rdlussĂŒmbol), kuna Unicode'i sĂŒmbolid, millel on samad kaalud, arvestatakse ekvivalentseteks sĂŒmboliteks.

Praeguse faili versiooni sektsiooni kogupikkus on umbes 900 rida. Olen nĂ€iteks vĂ€lja lĂ”iganud mitmest kohast, et nĂ€idata nimede juhuslikkust ja eri tĂŒĂŒpi sĂŒntaksit.

LC_COLLATE

collating-symbol 
collating-symbol 
collating-symbol 
collating-symbol 
...
collating-symbol 
collating-symbol 
collating-symbol 
...
collating-symbol ..
collating-symbol  % Garantiide suurim sĂŒmboli vÀÀrtus. Hoida loendi lĂ”pus
...
collating-element  from ""
collating-element  from ""

  • collating-symbol registreerib rea OSMANYA kaalude nimede tabelis
  • collating-symbol .. registreerib nimede jada, mis koosneb eesliitest S ja heksadetsimaalsest numbrilisest sufiksist, mis on 1D000 kuni 1D35F.
  • FFFF ja collating-symbol nĂ€ib olevat suur positiivne tĂ€isarv heksadetsimaalses sĂŒsteemis, kuid <SFFFF> on lihtsalt nimi, mis vĂ”iks vĂ€lja nĂ€ha nagu <VERYBIGVAL>
  • nimi <U0413> tĂ€hendab koodipunkti kodeeringus UCS-4
  • collating-element from "" registreerib uue nime kahele Unicode'i punktile.

Kui kaalude nimed on mÀÀratud, mÀÀratakse tegelikud kaalud. Kuna vĂ”rdlemisel on oluline ainult suhete mÀÀr ehitamiseks, siis mÀÀratakse kaalud lihtsa nimede loetelu jada kaudu. Esmalt loetletakse "kergemad" kaalud, seejĂ€rel "raskemad". Tuletan meelde, et iga Unicode'i sĂŒmbolile antakse neli erinevat kaalu. Siin on need koondatud ĂŒhte jĂ€rjestatud jadasse. Teoreetiliselt vĂ”ib iga sĂŒmboolne nimi olla kasutusel igal neljal tasemel, kuid kommentaarid osutavad, et arendajad jagavad nimed tasemete kaupa.

% SĂŒmboolsete kaalude mÀÀramised

% Kolmanda taseme kaalude mÀÀramised




...
% Teise taseme kaalude mÀÀramised

 % KOMBINERIV ALAJÕM
 % KOMBINERIV KOMMA ÜLE
 % KOMBINERIV PÖÖRDUMINE KUMMA ÜLE
...
% Esimese taseme kaalude mÀÀramised
 % HORIZONTAALNE TABULATSIOON
 % REAASTIMINE
 % VERTIKAALNE TABULATSIOON
...
 % KÜRILI KEELE VÄIKE KIRI DE
 % KÜRILI KEELE VÄIKE KIRI KOMI DE
 % KÜRILI KEELE VÄIKE KIRI DJE
 % KÜRILI KEELE VÄIKE KIRI KOMI DJE
 % KÜRILI KEELE VÄIKE KIRI GJE
 % KÜRILI KEELE VÄIKE KIRI ZE, MILLEL ON ALLA MINEK
 % KÜRILI KEELE VÄIKE KIRI IE
 % KÜRILI KEELE VÄIKE KIRI IE, MILLEL ON BREVI
 % KÜRILI KEELE VÄIKE KIRI UKRAINIAN IE
 % KÜRILI KEELE VÄIKE KIRI ZHE

LÔpuks, tabel koos kaaludega.

Kaalude sektsioon on joontega, mis sisaldavad vĂ”tmesĂ”nu order_start ja order_end. TĂ€iendavad parameetrid order_start mÀÀravad, millises suunas read igal vĂ”rdlemise tasemel vaadatakse. Vaikimisi kasutatakse parameetrit forward. Sektsiooni keha koosneb ridadest, mis sisaldavad sĂŒmboli koodi ja nelja selle kaalu. SĂŒmboli kood vĂ”ib olla esindatud kas sĂŒmbol ise, koodipunkt vĂ”i sĂŒmboolne nimi, mis on varem mÀÀratletud. Kaalu saab samuti mÀÀrata sĂŒmboolsete nimede, koodipunktide vĂ”i sĂŒmbolite kaudu. Kui kasutatakse koodipunkte vĂ”i sĂŒmboleid, siis nende kaal on samasugune kui koodipunkti numbriline vÀÀrtus (positsioon Unicode tabelis). SĂŒmbolid, mida ei ole selgelt mÀÀratletud (nii nagu ma aru saan), arvestatakse tabelisse peamise kaaluga, mis vastab positsioonile Unicode tabelis. Eriline kaalu vÀÀrtus IGNORE tĂ€hendab, et vastaval vĂ”rdlemise tasemel seda sĂŒmbolit ei arvestata.

Kaalude struktuuri demonstreerimiseks valisin kolm piisavalt ilmselget fragmenti:

  • sĂŒmbolid, mida tĂ€ielikult ignoreeritakse
  • sĂŒmbolid, mis on ekvivalentne numbrile kolm esimesel kahel tasemel
  • kiri kyrillises alfabeedis, mis ei sisalda diakriitilisi mĂ€rke ja seetĂ”ttu sorteeritakse peamiselt esimesel ja kolmandal tasemel.

order_start forward;forward;forward;forward,position
 IGNORE;IGNORE;IGNORE;IGNORE % NULL (in 6429)
 IGNORE;IGNORE;IGNORE;IGNORE % START OF HEADING (in 6429)
 IGNORE;IGNORE;IGNORE;IGNORE % START OF TEXT (in 6429)
...
 ;;; % DIGIT THREE
 ;;; % FULLWIDTH DIGIT THREE
 ;;; % PARENTHESIZED DIGIT THREE
 ;;; % DIGIT THREE FULL STOP
 ;;; % MATHEMATICAL BOLD DIGIT THREE
...
 ;;; % CYRILLIC SMALL LETTER A
 ;;; % CYRILLIC CAPITAL LETTER A
 ;;; % CYRILLIC SMALL LETTER A WITH BREVE
 ;;; % CYRILLIC SMALL LETTER A WITH BREVE
...
 ;;; % CYRILLIC SMALL LETTER BE
 ;;; % CYRILLIC CAPITAL LETTER BE
 ;;; % CYRILLIC SMALL LETTER VE
 ;;; % CYRILLIC CAPITAL LETTER VE
...
order_end

NĂŒĂŒd saab jĂ€lle naasta artikli alguse nĂ€idete sortimise juurde. Probleem peitub tabeli kaalu selles osas:

IGNORE;IGNORE;IGNORE; % SPACE
 IGNORE;IGNORE;IGNORE; % EXCLAMATION MARK
 IGNORE;IGNORE;IGNORE; % QUOTATION MARK
...

On nĂ€ha, et selles tabelis on kirjavahemĂ€rgid tabelist Pobitine vĂ”i pobaita rasteriseerimine (sealhulgas tĂŒhik) stringide vĂ”rdlemisel praktiliselt alati ignoreeritakse. Eranditeks on vaid read, mis kattuvad tĂ€ielikult, vĂ€lja arvatud kirjavahemĂ€rgid, mis esinevad kattuvates positsioonides. Minu nĂ€ite read (pĂ€rast sortimist) nĂ€evad vĂ€lja jĂ€rgmised:

AbakanovMihhailvÀrvija
JolkinaElakraanioperaator
IvanovaAllavÀrvija
IvanovAndrei puusepp

Arvestades, et kaalu tabelis kÀivad vene keeles suurtÀhed pÀrast vÀiketÀhti (kolmandal tasemel <CAP> raske kui <MIN>), sortimine nÀib tÀiesti korrektne.

Muutes muutuja LC_COLLATE=C laaditakse eriline tabel, mis mÀÀrab baitide vÔrdlemise

static const uint32_t collseqwc[] =
{
  8, 1, 8, 0x0, 0xff,
  /* 1st-level table */
  6 * sizeof (uint32_t),
  /* 2nd-level table */
  7 * sizeof (uint32_t),
  /* 3rd-level table */
  L'x00', L'x01', L'x02', L'x03', L'x04', L'x05', L'x06', L'x07',
  L'x08', L'x09', L'x0a', L'x0b', L'x0c', L'x0d', L'x0e', L'x0f',

...
  L'xf8', L'xf9', L'xfa', L'xfb', L'xfc', L'xfd', L'fe', L'xff'
};

Kuna Unicode'is on tÀhemÀrk Ё enne A, sorteeritakse read vastavalt.

Tekstilised ja binaarsed tabelid

On ilmne, et stringide vĂ”rreldamine on ÀÀrmiselt sagedane operatsioon ja tabeli analĂŒĂŒs lisast mĂ”nevĂ”rra kulukas protseduur. Tabeli juurdepÀÀsu optimeerimiseks kompileeritakse see binaarfaili kujule kĂ€su localedef.

Meeskond localedef mis vĂ”tab parameetritena faili riiklike eripĂ€rade tabeliga (valik -i), milles kĂ”ik sĂŒmbolid on esitatud Unicode'i punktidena, ja faili, mis seondab Unicode'i punktid konkreetses kodeeringus sĂŒmbolitega (valik -f). Töö tulemusena luuakse binaarfailid lokaali jaoks, mille nimi on mÀÀratud viimases parameetris.

Glibc toetab kahte tĂŒĂŒpi binaarfailide formaate: "traditsiooniline" ja "kaasaegne".

Traditsiooniline formaat tÀhendab, et lokaali nimi on nimekiri alla kaustas /usr/lib/locale/. Sellel alamkaustal hoitakse binaarfailide LC_COLLATE, LC_CTYPE, LC_TIME jne. Fail LC_IDENTIFICATION sisaldab lokaali formaalset nime (mis vÔib erineda kausta nimest) ja kommentaare.

Kaasaegne formaat eeldab, et kĂ”ik lokaalid hoitakse ĂŒhes arhiivis /usr/lib/locale/locale-archive, mis kaardistatakse virtuaalsesse mĂ€llu kĂ”igile protsessidele, mis seda kasutavad glibc. Kaasaegses formaadis nimetatakse lokaali nime teatud kanoniseerimisele — kodeeringu nimedes jÀÀvad ainult numbrid ja tĂ€hed, mis on muudetud vĂ€ikesteks tĂ€htedeks. Nii ru_RU.KOI8-R, salvestatakse kui ru_RU.koi8r.

Sisendfailid otsitakse jooksva kausta ning kaustade /usr/share/i18n/locales/ ja /usr/share/i18n/charmaps/ failide lisast ja kodeeringute failide vastavalt.

NÀiteks kÀsk

localedef -i ru_RU -f MAC-CYRILLIC ru_RU.MAC-CYRILLIC

kompileerib faili /usr/share/i18n/locales/ru_RU kasutades kodeerimisfaili /usr/share/i18n/charmaps/MAC-CYRILLIC.gz ja salvestab tulemuse /usr/lib/locale/locale-archive koos nimega ru_RU.maccyrillic

Kui keskkonnamuutuja LANG=en_US.UTF-8 siis glibc otsib lokaali binaarfailide jÀrgmist jÀrgnevate failide ja kaustade jÀrjekorras:

/usr/lib/locale/locale-archive
/usr/lib/locale/en_US.UTF-8/
/usr/lib/locale/en_US/
/usr/lib/locale/enUTF-8/
/usr/lib/locale/en/

Kui lokaal esineb nii traditsioonilistes kui ka kaasaegsetes formaatides, antakse eelnev kaal kaasaegsele.

Koostatud lokaalide nimekirja saab vaadata kÀsuga locale -a.

Oma vÔrdlustabeli ettevalmistamine

NĂŒĂŒd, varustatud teadlike teadmistega, saab luua oma ideaalse stringide vĂ”rdlustabeli. See tabel peab Ă”igesti vĂ”rreldama vene tĂ€hti, sealhulgas tĂ€hti Ё, arvestades samas ka kirjavahemĂ€rke vastavalt tabelile Pobitine vĂ”i pobaita rasteriseerimine.

Oma sortimisse tabeli ettevalmistamise protsess koosneb kahest etapist: kaalutabeli redigeerimisest ja selle binaarfailiks kompileerimisest kÀsuga localedef.

Kuna vÔrreldava tabeli kohandamine minimaalse redigeerimise kuludega on vÔimalik, on formaadis ISO 14652 on olemas olemasoleva tabeli kaalu kohandamise sektsioonid. Sektsioon algab vÔtmesÔnast reorder-after ja positsiooni nÀitamisest, mille jÀrel asendamine toimub. Sektsiooni lÔpetab rida reorder-end. Kui tabeli mitmeid osi tuleb kohandada, luuakse iga sellise osa jaoks oma sektsioon.

Ma kopeerisin uued faili versioonid iso14651_t1_common ja ru_RU repositooriumist glibc oma kodukatalooge ~/.local/share/i18n/locales/ ja redigeerisin osakonda natuke. LC_COLLATE ja ru_RU. Uued faili versioonid on tĂ€ielikult ĂŒhilduvad minu versiooniga glibc. Kui soovite kasutada vanemaid faili versioone, peate muutma sĂŒmboolseid nimesid ja asukohta, kust asendamine algab tabelis.

LC_COLLATE
% Kopeerige mall ISO/IEC 14651-st
copy "iso14651_t1"
reorder-after 
 ;;; % SPACE
 ;;; % EXCLAMATION MARK
 ;;; % QUOTATION MARK
...
 ;;; % RIGHT CURLY BRACKET
 ;;; % TILDE
reorder-end
END LC_COLLATE

Tegelikult oleks pidanud vÀljad muutma LC_IDENTIFICATION nii, et need viitavad lokaali ru_MY, kuid minu nÀites ei olnud seda vaja, kuna ma jÀtsin vÀlja lokaalisalad locale-archive.

Et localedef töötas failidega minu kaustas lÀbi muutuja I18NPATH vÔib lisada lisakausta sisendfailide otsimiseks, ja binaarfailide salvestamise katalooge saab mÀÀrata tee kaudu, mis on slÀshidega:

$> I18NPATH=~/.local/share/i18n localedef -i ru_RU -f UTF-8 ~/.local/lib/locale/ru_MY.UTF-8

POSIX-i eeldab, et LANG vĂ”ib kirjutada absoluutteed failide kataloogide jaoks, mis algavad sirgest slĂ€shist, kuid glibc ja Linux kĂ”ik teed loetakse aluskataloogist, mille saab ĂŒle mÀÀrata muutuja LOCPATH. PĂ€rast seadistamist LOCPATH=~/.local/lib/locale/ kĂ”ik lokaliseerimisega seotud failid otsitakse ainult minu kaustast. Lokaali arhiiv seadistatud muutuja korral LOCPATH ignored.

Siin on otsustav test:

$> LANG=ru_MY.UTF-8 LOCPATH=~/.local/lib/locale/ sort buhg.txt
Abakanov Mihhail;maalija
Jolkina Ella;kraanajuht
Ivanov Andre;torulukksepp
Ivanova Alla;advokaat

Hurraa! Me tegime selle Àra!

Töötamine vigade kallal

Olen juba vastanud alguses esitatud ridade sortimise kĂŒsimustele, kuid on veel paar kĂŒsimust vigade kohta - nĂ€htavad ja nĂ€htamatud.

Naaseme algse ĂŒlesande juurde.

Ja programm sort ja programm join kasutavad samu stringide vĂ”rdlemise funktsioone glibc. Kuidas see juhtus, et join nĂ€itas sorteerimise viga ridade puhul, mis olid sorteeritud kĂ€suga sort kohalikus en_US.UTF-8? ОтĐČДт ĐżŃ€ĐŸŃŃ‚: sort vĂ”rdleb rida tĂ€ielikult, kuid join vĂ”rdleb ainult mĂ€rksĂ”na, milleks on vaikimisi rida kuni esimese tĂŒhiku sĂŒmbolini. Minu nĂ€ites pĂ”hjustas see veateate, kuna ridade esimeste sĂ”nade sorteerimine ei klappinud tĂ€isridade sorteerimisega.

Kohalik "C" tagab, et sorteeritud ridades on algsed alampead sĂ”nad kuni esimese tĂŒhiku sĂŒmbolini samuti sorteeritud, kuid see varjab vaid viga. VĂ”ib leida selliseid andmeid (inimesed, kellel on samad perekonnanimed, kuid erinevad eesnimed), mis annavad vale faili ĂŒhendamise tulemuse ilma veateateta. Kui soovime, et join ĂŒhendaks failide ridu perekonna- ja eesnime jĂ€rgi, siis Ă”ige viis oleks eraldaja mÀÀramine ja nende sorteerimine mĂ€rksĂ”na jĂ€rgi, mitte kogu rea jĂ€rgi. Sel juhul toimub ka ĂŒhendamine Ă”igesti ja mingis kohalikus ei esine vigu:

$> sort -t ; -k 1 buhg.txt > buhg.srt
$> sort -t ; -k 1 mail.txt > mail.srt
$> join -t ; buhg.srt mail.srt > result

Edukalt lĂ”petatud nĂ€ide kodeeringus CP1251 kĂ€tkeb veel ĂŒht viga. Nimelt on kĂ”igis minu teadaolevates distributsioonides Linux pakettides puuduv kompileeritud kohalik ru_RU.CP1251. Kui kompileeritud kohalikku ei leita, siis sort kasutatakse vaikselt byte-tasemel vĂ”rdlemist, mida me olime ka nĂ€inud.

Muide, on ka veel ĂŒks vĂ€ike tĂ”rge, mis on seotud kompileeritud lokalite puudumisega. KĂ€sk LOCPATH=/tmp locale -a annab vĂ€lja kĂ”igi lokalite loendi locale-archive, kuid seatud muutuja LOCPATH kĂ”ikide programmide (sealhulgas locale) jaoks ei ole need kohalikud saadaval.

$> LOCPATH=/tmp locale -a | grep en_US
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_COLLATE to default locale: No such file or directory
en_US
en_US.iso88591
en_US.iso885915
en_US.utf8

$> LC_COLLATE=en_US.UTF-8 sort --debug
sort: using ‘en_US.UTF-8’ sorting rules

$> LOCPATH=/tmp LC_COLLATE=en_US.UTF-8 sort --debug
sort: using simple byte comparison

KokkuvÔte

Kui oled programmeerija, kes harjunud arvama, et read on byte'ide kogum, siis on sinu valik LC_COLLATE=C.

Kui oled lingvist vÔi sÔnaraamatute koostaja, siis on sul parem oma kohalik kompileerida.

Kui oled tavaline kasutaja, siis piisab, kui harjuda sellega, et kÀsk ls -a annab vÀlja faile, mis algavad punktiga, koos failidega, mis algavad tÀhega, ja Midnight Commander, mis kasutab oma sisemisi funktsioone nimede sortimiseks, viib failid, mille nimi algab punktiga, loendi ette.

Viidatud lingid

Aruanne nr 10 Unicode sortimisalgoritmi kohta

SĂŒmbolite kaalud unicode.org-is

ICU — teostus IBM-i Unicode'i töötlemise raamatukogust.

Sorteerimistest ICU

SĂŒmbolite kaalud Rahvusvaheline stringide jĂ€rjestamise ja vĂ”rdlemise

Faili formaadi kirjeldus kaaludega ISO 14652

Kettide vÔrdlemise arutelu glibc

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster