Sissejuhatus
KĂ”ik algas lĂŒhikesest skriptist, mis pidi ĂŒhendama teabe töötajate e-posti aadresside kohta, e-mail mis saadud e-posti loendi kasutajate nimekirjast, koos töötajate ametikohtadega, mis saadi personaliosakonna andmebaasist. MĂ”lemad nimekirjad eksporditi tekstifailidesse Unicode kodeeringuga, UTF-8 ja salvestati Unix'i ridade lĂ”ppudega.
Sisu mail.txt
Ivanov Andrei;ia@example.comSisu buhg.txt
Ivanova Alla;maaler
Jolkina Ella;kraanajuhiks
Ivanov Andrei;torumees
Abakanov Mihhail;maalerFailide ĂŒhendamiseks sorteeriti need Unix'i kĂ€suga sort ja edastati Unix'i programmile, liitu, mis lĂ”petas ootamatult vea 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 Andrei;torumeesSorteerimise tulemuse visuaalne kontroll nĂ€itas, et ĂŒldiselt on sorteerimine Ă”ige, kuid meessoost ja naissoost perekonnanimede kattumiste korral on naised enne mehi:
$> sort buhg.txt
Abakanov Mihhail;maaler
Jolkina Ella;kraanajuhiks
Ivanova Alla;maaler
Ivanov Andrei;torumeesTundub nagu Unicode sorteerimise viga vÔi nagu feminism sorteerimisalgoritmis. Esimene, muidugi, on usutavam.
JĂ€tame praegu kĂ”rvale liitu ja keskendume sort. Proovime ĂŒlesannet lahendada katsetamise meetodil. Alguseks muutkem kohaleks en_US jĂ€rgnevaga et_RU. Sorteerimiseks piisaks keskkonnamuutuja seadmisest LC_COLLATE, aga me ei jÀÀ selliste vĂ€ikeste asjadega vaeva:
$> LANG=et_RU.UTF-8 sort buhg.txt
Abakanov Mihhail;vÀrvija
Jolkina Ella;kraanajuhataja
Ivanova Alla;vÀrvija
Ivanov Andrei;torumeesMidagi ei ole muutunud.
Proovime faile ĂŒhebaidise kodeeringuga ĂŒmber kodeerida:
$> iconv -f UTF-8 -t KOI8-R buhg.txt
| LANG=et_RU.KOI8-R sort
| iconv -f KOI8-R -t UTF8Taaskord ei ole midagi muutunud.
Midagi ei ole teha, tuleb leida lahendus internetist. Otseses mĂ”ttes venekeelsete perekonnanimede kohta pole midagi, aga on kĂŒsimusi teiste sorteerimise eriskummaliste asjade kohta. NĂ€iteks selline probleem: . LĂŒhidalt öeldes, read "a-b", "aa", "ac" sorteeritakse nagu "aa", "a-b", "ac".
Vastus on igal pool standardne: kasutage programmeerija kohalikke seadeid "C" ja siis on teil Ônn. Proovime:
$> LANG=C sort buhg.txt
Jolkina Ella;kraanajuhataja
Abakanov Mihhail;vÀrvija
Ivanov Andrei;torumees
Ivanova Alla;advokaatMidagi on muutunud. Ivanovâid on Ă”iges jĂ€rjekorras, kuid Jolkina on kuhugi kadunud. Naaseme algsele ĂŒlesandele:
$> LANG=C sort buhg.txt > buhg.srt
$> LANG=C sort mail.txt > mail.srt
$> LANG=C join buhg.srt mail.srt > resultSee toimis ilma vigadeta, nagu lubas internet. Ja see on vaatamata Đlkini esimesele reale.
Probleem nĂ€ib olevat lahendatud, kuid igaks juhuks proovime veel ĂŒht 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, nagu imelik see ka ei oleks, vastab lokaadile "C", ja kogu nĂ€ide seega lĂ€bib ilma vigadeta. Milline mĂŒstika.
Ma ei armasta mĂŒstikat programmeerimises, kuna see varjab tavaliselt vigu. Pean tĂ”siselt tegelema kĂŒsimusega, kuidas see töötab sort ja millele see mĂ”ju avaldab LC_COLLATE .
LĂ”puks pĂŒĂŒan vastata kĂŒsimustele:
- miks sorteeriti valejÀrjekorras naissoost perekonnanimesid
- miks LANG=ru_RU.CP1251 osutus ekvivalendiks LANG=C
- miks on sort ja liitu erinevad arusaamad sorteeritud ridade jÀrjekorrast
- miks kÔigis mu nÀidetes on vigu
- lÔpuks, kuidas sorteerida ridu oma maitse jÀrgi
Sorteerimine Unicode'is
Esimene peatus on tehniline aruanne nr 10 pealkirjaga veebisaidil . Aruanne sisaldab palju tehnilisi detaile, seega luban endale tuua lĂŒhikese ĂŒlevaate pĂ”hiteemadest.
Sorteerimine â "string comparison" on the basis of any sorting algorithm. The algorithms can differ ("bubble", "merge", "quick"), but they all rely on comparing pairs of strings to establish their order.
Sorting strings in natural language is quite a complex issue. Even in the simplest single-byte encodings, the order of letters in an alphabet that differs from the English Latin alphabet won't match the numerical values by which these letters are encoded. For example, in the German alphabet, the letter Ă is positioned between Umbes ja P, while in the encoding CP850 it falls between Ăż ja Ă.
One could try to abstract from a specific encoding and consider "ideal" letters arranged in a certain order, as done in Unicode. Encodings UTF8, UTF16 or single-byte KOI8-R (if a limited subset of Unicode is needed) will provide different numerical representations of letters but will refer to the same elements in the basic table.
Selgub, et isegi sĂŒmbolite tabeli nullist koostamisel ei suuda me sellele mÀÀrata universaalset sĂŒmbolite jĂ€rjestust. Erinevates rahvuslikes tĂ€hestikes, mis kasutavad samu tĂ€hti, vĂ”ib nende tĂ€hede jĂ€rjestus erineda. NĂ€iteks prantsuse keeles Ă peetakse ligatuuriks ja seda sorteeritakse kui stringi. AETaas, norski keeles Ă on see eraldi tĂ€ht, mis paikneb pĂ€rast Z. Muide, lisaks ligatuuridele nagu Ă on olemas tĂ€hed, mis on kirjutatud mitme sĂŒmboliga. Nii on TĆĄehhi tĂ€hestikus tĂ€ht Ch, mis asub nende vahel H ja I.
Lisaks tĂ€hestike erinevustele on olemas ka teised rahvuslikud traditsioonid, mis mĂ”jutavad sorteerimist. Eriti tĂ”statub kĂŒsimus: millises jĂ€rjekorras peaksid sĂ”naraamatutes esinduma suurtĂ€hed ja vĂ€iketĂ€hed? Samuti vĂ”ivad sorteerimist mĂ”jutada erimĂ€rgid. Hispaania keeles asetatakse kĂŒsimuse algusesse pööratud kĂŒsimĂ€rgi mĂ€rk (ÂżTe gusta la mĂșsica?). Sel juhul on ilmne, et kĂŒsimustikud ei peaks olema eraldi rĂŒhmitatud vĂ€ljaspool tĂ€hestikku, vaid kuidas jĂ€rjestada ridu koos teiste kirjavahemĂ€rgiga?
Ma ei kavatse peatuda ridade jĂ€rjestamisele keeltes, mis erinevad tugevasti Euroopa keeltest. MĂ€rgin, et paremale vĂ”i ĂŒlespoole kirjutamise suunaga keeltes hoitakse sĂŒmboleid ridades tĂ”enĂ€oliselt lugemisjĂ€rjestuses, ning ka mitte-tĂ€heline kirjutamine omab oma viise ridade sĂŒmbolite jĂ€rjekorra seadmiseks. NĂ€iteks vĂ”ivad hieroglĂŒfid olla jĂ€rjestatud vastavalt kirjutusviisile () vĂ”i hÀÀldusele. Kuidas emojid peaksid olema jĂ€rjestatud, ma ausalt öeldes ei tea, kuid ka nende jaoks vĂ”iks midagi vĂ€lja mĂ”elda.
Ălaltoodud omaduste pĂ”hjal on vĂ€lja töötatud peamised nĂ”uded ridade vĂ”rdlemiseks, mis pĂ”hinevad Unicode tabelitel:
- ridade vĂ”rdlemine ei sĂ”ltu sĂŒmbolite asukohast kooditabelis;
- sĂŒmbolite jĂ€rjestused, mis moodustavad ĂŒhe sĂŒmboli, viiakse kanonilisse vormi (A + ĂŒlemine ring see on sama mis Ă );
- stringide vĂ”rdlemisel vĂ”etakse sĂŒmbol arvesse kontekstis ja vajadusel ĂŒhendatakse see naabersĂŒmbolitega ĂŒheks vĂ”rdlemiseĂŒksuseks (Ch tĆĄehhi keeles) vĂ”i jagatakse mitmeks (Ă prantsuse keeles);
- kÔik rahvuslikud omadused (tÀhestik, suure-/vÀikese tÀhtede erinevus, kirjavahemÀrgid, kirjutamise viiside jÀrjekord) peavad olema seadistatavad kuni kÀsitsi mÀÀratud jÀrjekorrani (emoji);
- vĂ”rdlemine on oluline mitte ainult sortimise jaoks, vaid ka paljude teiste kohtade jaoks, nĂ€iteks stringide vahemike mÀÀramiseks (asendus {A⊠Ń} in bash);
- vÔrdlemine peab toimuma piisavalt kiiresti.
Lisaks on aruande autorid formuleerinud vÔrdlemise omadused, millele algoritmi arendajad ei peaks tuginema:
- vĂ”rdlemise algoritm ei tohiks nĂ”uda iga keele jaoks eraldi sĂŒmbolite kogumit (vene ja ukraina keel kasutavad suuresti samu kirillitsa sĂŒmboleid);
- vĂ”rdlemine ei tohiks tugineda sĂŒmbolite jĂ€rjekorrale Unicode tabelites;
- stringi kaal ei tohiks olla stringi atribuut, kuna sama string erinevates kultuurilistes kontekstides vÔib omada erinevat kaalu;
- tekstide kaalud vÔivad muutuda sulandumisel vÔi jagunemisel (nÀiteks x < y ei tÀhenda, et xz < yz);
- erinevad tekstid, millel on samad kaalud, loetakse sortimisalgoritmi seisukohalt vÔrdsed. TÀiendava jÀrjestuse kehtestamine nende tekstide vahel on vÔimalik, kuid see vÔib halvendada jÔudlust;
- korduvate sortimiste puhul vÔivad vÔrdselt kaalutud tekstid omavahel kohtasid vahetada. Stabiilsus on konkreetse sortimisalgoritmi omadus, mitte tekstide vÔrdlemise algoritmi omadus (vt eelmist punkti);
- sortimisreeglid vÔivad aja jooksul muutuda kultuuriliste traditsioonide tÀpsustamise/muutmise tÔttu.
Samuti on sÀtestatud, et vÔrdlemisalgoritm ei tea midagi vÔrreldavate tekstide semantikast. Seega ei tohiks numbritest koosnevaid tekstid vÔrrelda numbritena ning ingliskeelsetes nimedes ei tohi artiklit vÀlja jÀtta (Beatles, The).
KÔikide tÔstatatud nÔuete rahuldamiseks on vÀlja töötatud mitmetasandiline (tegelikult neljatase) tabeli sortimisalgoritm.
Eelnevalt tuuakse stringi sĂŒmbolid kanoniliseks ja rĂŒhmitatakse vĂ”rdlemiseks ĂŒhikuteks. Iga vĂ”rdlusĂŒhikule omistatakse mitu kaalu vastavalt erinevatele vĂ”rdlustasanditele. VĂ”rdlusĂŒksuste kaalud on jĂ€rjestatud hulkade elemendid (antud juhul tĂ€isarvud), mida saab vĂ”rrelda suurem-vĂ€hem suhtega. Eriline vÀÀrtus IGNORED (0x0) tĂ€hendab, et vastaval vĂ”rdlustasandil antud ĂŒksus ei osale vĂ”rdluses. Stringide vĂ”rdlemine vĂ”ib toimuda korduvalt, kasutades vastavate tasemete kaalu. Iga taseme vĂ”rdlusĂŒhikute kaalu vĂ”rreldakse jĂ€rjestikku omavahel.
Erinevates algoritmi rakendustes eri rahvuslike traditsioonide jaoks vĂ”ivad koefitsientide suurused erineda, kuid Unicode'i standardisse kuulub pĂ”hikaalu tabel â "Default Unicode Collation Element Table" (DUCET). Tahan mĂ€rkida, et muutuja seadistamine LC_COLLATE on tegelikult viide kaalutabeli valimisele stringide vĂ”rdluse funktsioonis.
Kaalukoefitsiendid DUCET on organiseeritud jÀrgmiselt:
- esimese taseme puhul muudetakse kĂ”ik tĂ€hed ĂŒhte soovitud suurusesse, diakriitilised mĂ€rgid jĂ€etakse vĂ€lja, kirjavahemĂ€rgid (kuid mitte kĂ”ik) ignoreeritakse;
- teise taseme puhul arvestatakse ainult diakriitilisi mÀrke;
- kolmanda taseme puhul arvestatakse ainult tÀhte suurust;
- neljanda taseme puhul arvestatakse ainult kirjavahemÀrke.
VÔrdlemine toimub mitmes etapis: kÔigepealt vÔrreldakse esimesel tasemel koefitsiente; kui kaalud kokkusobivad, jÀrgneb uuesti vÔrreldes teisel tasemel; seejÀrel vÔib lÀbi viia ka kolmanda ja neljanda taseme.
VĂ”rdlemine lĂ”peb, kui ridades leidub vastanduvad vĂ”rdlemise ĂŒksused erinevate kaalu jĂ€rgi. Ridu, millel on kĂ”ikidel neljal tasemel vĂ”rdne kaal, peetakse ĂŒksteisega vĂ”rdsed.
See algoritm (koos paljude lisatehniliste detailidega) andis aruande nr 10 nime â "Unicode Collation Algorithm" (UCA).
Selles kohas muutub meie nÀite sortimis kÀitumine natuke arusaadavamaks. Oleks hea vÔrrelda seda Unicode'i standardiga.
Teostuste testimiseks UCA on olemas spetsiaalne , kasutades , mis rakendab DUCET. Kaalu failis on erinevaid huvitavaid asju. NĂ€iteks on seal mĂ€nge mahjongi ja Euroopa domino joonestus ning kaardikomplekti mastide jĂ€rjestus (sĂŒmbol 1F000 ja edasi). Kaardimastid on paigutatud vastavalt bridĆŸi reeglitele â PCHBT, ning mastidesse kuuluvad kaardid on jĂ€rjestatud jĂ€rjehoidjate jĂ€rgi T, 2, 3⊠K.
Reaalse ridade sortimise Ă”iguse kontrollimine vastavalt DUCET oleks ĂŒsna kurnav, kuid Ă”nneks meie jaoks on olemas suurepĂ€rane rakendus Unikoodi raamatukogu jaoks â "" (ICU).
Selle raamatukogu veebisaidil, mis on loodud IBM, on demonstreerivad lehed, sealhulgas . Sisestame meie testitavad stringid vaikeseadistustega ja, oh imet, saame ideaalse vene sortimise.
Abakanov Mihhail;vÀrvimees
Jolkina Ella;kraanaoperaator
Ivanov Andre;torumees
Ivanova Alla;advokaatMuide, saidilt ICU vÔib leida tÀpsustusi vÔrdlemise algoritmi töö kohta kirjavahemÀrkide kÀsitlemisel. NÀiteks ignoreeritakse apostroof ja sidekriips.
Unikood aitas meid, kuid kummalise kĂ€itumise pĂ”hjuseid sort ĂŒhes Linux peab otsima mujalt.
Sortimine glibc
Kiire ĂŒlevaade tööriista lĂ€htekoodidest sort kohast GNU Core Utils nĂ€itas, et tööriist ise lokaliseerimine piirneb praeguse muutuja vÀÀrtuse prindimisega LC_COLLATE kĂ€ivitamisel silumisreĆŸiimis:
$ sort --debug buhg.txt > buhg.srt
sort: kasutab âen_US.UTF8â sorteeringureegleidStringide vĂ”rdlemine toimub standardse funktsiooni strcoll, seega on kĂ”ik huvitav juba raamatukogus glibc.
VDS-l on vĂ”imalik installida: wiki projekt glibc stringide vĂ”rdlemisega tegeleb . Sellest lĂ”igust vĂ”ib jĂ€reldada, et glibc sorteerimine pĂ”hineb juba tuttaval algoritmil UCA (The Unicode collation algorithm) ja/vĂ”i sarnasel standardil ISO 14651 (Rahvusvaheline stringide jĂ€rjestamine ja vĂ”rdlemine). Mis puudutab viimast standardit, siis tuleks mĂ€rkida, et saidil ISO 14651 on ametlikult kuulutatud avalikuks, kuid vastav link viib olematusse lehte. Google annab mitu lehte, kus on lingid ametlikele saitidele, mis pakuvad standardi elektroonilise koopia ostmist sada eurot, kuid kolmanda-neljanda lehe otsingutulemustes leiab ka otse lingid PDF. Ăldiselt ei erine standard praktiliselt UCA, kuid loetakse igavamalt, kuna see ei sisalda silmapaistvaid nĂ€iteid riiklike eripĂ€rade sorteerimisel.
KĂ”ige huvitavam teave oli wiki link stringide vĂ”rdlemise rakendamise arutamiseks glibc. Arutelust selgub, et glibc stringide vĂ”rdlemiseks kasutatakse ISOĂŒht tabelit (CTT), mille aadressi leiate rakendusest A standardist ISO 14651. Aastatel 2000 kuni 2015 ei olnud sellel tabelil hooldajat ja see erineb mĂ€rgatavalt (vĂ€hemalt visuaalselt) praegusest standardi versioonist. Aastatel 2015 kuni 2018 toimus kohandamine uue versiooni tabeliga ja hetkel on teil vĂ”imalus kohtuda reaalses elus nii uue versiooniga ( glibc ) kui ka vanaga (CentOS 8NĂŒĂŒd, kui kogu teave algoritmi ja abitablettide kohta on olemas, saame naasta algse probleemi juurde ja mĂ”ista, kuidas Ă”igesti jĂ€rjestada stringe vene lokaalis.CentOS 7).
ISO 14651/14652
Meid huvitava tabeli lÀhtekood
enamikus distributsioonides CTT asub kataloogis Linux . Ainult tabel asub failis /usr/share/i18n/locales/iso14651_t1_common . SeejÀrel kaasatakse see fail direktiivigacopy iso14651_t1_common faili iso14651_t1 , mis omakorda on kaasatud riiklikele failidele, sealhulgas. Enamikus distributsioonides en_US ja et_RU. Enamikus jaotustes Linux kÔik algfailid on lisatud pÔhivaru, kuid kui neid pole, peate installima tÀiendava paketi jaotusest.
Faili struktuur , mis omakorda on kaasatud riiklikele failidele, sealhulgas see vĂ”ib tunduda kohutavalt sĂ”nakas, ebamugavate nimevormingureeglitega, kuid kui vaadata, on see piisavalt lihtne. Struktuur on kirjeldatud standardis ISO 14652, mida saab alla laadida veebisaidilt . Veel ĂŒht faili formaadi kirjelduse saab lugeda POSIX alates OpenGroup. Standardi lugemise alternatiivina saab uurida funktsiooni allikaid collate_read ĂŒhes glibc/locale/programs/ld-collate.c.
Faili struktuur nÀeb vÀlja jÀrgmine:
Vaikimisi kasutatakse sĂŒmbolit kui maskeerimissĂŒmbolit ning reavahetus sĂŒmbolist # on kommentaar. MĂ”lemat sĂŒmbolit saab ĂŒle kirjutada, nagu on tehtud uues tabeli versioonis:
escape_char /
comment_char %Failis vĂ”ivad esineda tokenid formaadis <Uxxxx> vĂ”i <Uxxxxxxxx> (kus x â kuusnurkne number). See on kuusnurkne esitus Unicode'i koodipunktide UCS-4 (UTF-32). KĂ”ik ĂŒlejÀÀnud elemendid nurgasulgudes (sealhulgas <Uxxxx_xxxx>, <2> ja sarnased) on peetud lihtsakste stringikonspektideks, millel ei ole konteksti vĂ€ljaspool erilist tĂ€hendust.
String LC_COLLATE ĂŒtleb meile, et edasi algavad andmed, mis kirjeldavad stringide vĂ”rdlemist.
Esiteks mÀÀratakse kaalu nimed vĂ”rdlustabelis ning tĂ€hemĂ€rkide kombinatsioonide nimed. Ăldiselt kuuluvad kaks tĂŒĂŒpi nimesid kahele erinevale entiteedile, kuid tegelikus failis on need segamini. Kaalu nimed mÀÀratakse mĂ€rksĂ”naga collating-symbol (vĂ”rdlemise sĂŒmbol), kuna Unicode'i sĂŒmbolid, millel on samad kaalud, peetakse ekvivalentseteks sĂŒmboliteks.
Jooksva faili versiooni sektsiooni kogupikkus on umbes 900 rida. Olen vĂ”tnud nĂ€iteid mitmest kohast, et nĂ€idata nimede meelevaldsust ja mitut tĂŒĂŒpi sĂŒntaksit.
LC_COLLATE
collating-symbol
collating-symbol
collating-symbol
collating-symbol
...
collating-symbol
collating-symbol
collating-symbol
...
collating-symbol ..
collating-symbol % garantii suurim sĂŒmbolivÀÀrtus. Hoidke selle nimekirja lĂ”pus
...
collating-element from ""
collating-element from ""- collating-symbol registreerib stringi OSMANYA kaalu nimede tabelis
- collating-symbol .. registreerib nimejĂ€rjestuse, mis koosneb eesliitest S ja kuuekĂŒmnendkĂŒmnendast numbrilisest sufiksist alates 1D000 kuni 1D35F.
- FFFF ĂŒhes collating-symbol nĂ€eb vĂ€lja nagu suur mĂ€rkidevaheline tĂ€isarv kuuekĂŒmnendkĂŒmnendises sĂŒsteemis, kuid <SFFFF> on lihtsalt nimi, mis vĂ”iks vĂ€lja nĂ€ha nagu <VERYBIGVAL>
- nimi <U0413> tÀhendab koodpunkti kodeeringus UCS-4
- collating-element from "" registreerib uue nime kahele Unicode'i punktile.
Kui kaalud on mÀÀratud, mÀÀratakse tegelikud kaalud. Kuna vĂ”rdlemisel on oluline ainult suuremate-vĂ€iksemate suhted, mÀÀratakse kaalud lihtsa nime loetelu jĂ€rgi. Esiteks loetletakse "kergemad" kaalud, seejĂ€rel "raskaamad". Pean meenutama, et igale Unicode'i sĂŒmbolile antakse neli erinevat kaalu. Need on koondatud ĂŒhte jĂ€rjestatud jĂ€rjestusse. Teoreetiliselt vĂ”ib iga sĂŒmboolne nimi olla kasutatud mis tahes neljal tasemel, kuid kommentaarides mĂ€rgitakse, et arendajad mĂ”tlevad nimed tasemetena.
% SĂŒmbolite kaalude mÀÀramine
% Kolmanda taseme kaalude mÀÀramine
...
% Teise taseme kaalude mÀÀramine
% ĂHENDAMINE MADALALINNA
% ĂHENDAMINE KOMA ĂLE
% ĂHENDAMINE PĂĂRDKOMA ĂLE
...
% Esimese taseme kaalude mÀÀramine
% HORIZONTAL TABULATSIOON
% RIDA KATKESTUS
% VERTIKAALNE TABULATSIOON
...
% KĂRILI KERGE TĂHE DE
% KĂRILI KERGE TĂHE KOMI DE
% KĂRILI KERGE TĂHE DJE
% KĂRILI KERGE TĂHE KOMI DJE
% KĂRILI KERGE TĂHE GJE
% KĂRILI KERGE TĂHE ZE KAEGA
% KĂRILI KERGE TĂHE IE
% KĂRILI KERGE TĂHE IE BREVEGA
% KĂRILI KERGE TĂHE UKRAINLAINE IE
% KĂRILI KERGE TĂHE ZHELĂ”puks on ise kaalu tabel.
Kaalude sektsioon on raamis koos mĂ€rksĂ”nadega order_start ja order_end. TĂ€iendavad parameetrid order_start mÀÀravad, millises suunas ridasid igal vĂ”rreldava tasemel vaadataks. VaikesĂ€tetena kasutatakse parameetrit forward. Sektsiooni sisu koosneb ridadest, mis sisaldavad sĂŒmbolikoodi ja nelja selle kaalu. SĂŒmbolikood vĂ”ib olla esindatud sĂŒmbol ise, koodipunkt vĂ”i varasemalt mÀÀratletud sĂŒmboolne nimi. Kaaled saab samuti mÀÀrata sĂŒmboolsete nimede, koodipunktide vĂ”i ise sĂŒmbolite kaudu. Kui kasutatakse koodipunkte vĂ”i sĂŒmboleid, on nende kaal kooskĂ”las koodipunkti numbrilise vÀÀrtusega (positsioonis Unicode tabelis). Ekslikult mitteĂŒles mĂ€rgitud sĂŒmbolid (nagu ma aru saan) loetakse tabelis, mille esmane kaal vastab nende positsioonile Unicode tabelis. Eriline kaal vÀÀrtus IGNORE tĂ€hendab, et vastaval vĂ”rdlustasemel antud sĂŒmbolit ignoreeritakse.
Kaalustruktuuri demonstreerimiseks valisin kolm piisavalt selget fragmenti:
- sĂŒmbolid, mida ignoreeritakse tĂ€ielikult
- sĂŒmbolid, mis on ekvivalentne numbriga kolm esimesel kahel tasemel
- vene tÀhestiku algus, mis ei sisalda diakriitilisi mÀrke ja seetÔttu sorteeritakse peamiselt esimese ja kolmanda taseme jÀrgi.
tellimus_algus edasi;edasi;edasi;edasi,positsioon
IGNORE;IGNORE;IGNORE;IGNORE % NULL (in 6429)
IGNORE;IGNORE;IGNORE;IGNORE % PEALKIRJA ALGUS (in 6429)
IGNORE;IGNORE;IGNORE;IGNORE % TEKSTI ALGUS (in 6429)
...
;; ; % KOLMOND DIGIT
;; ; % TĂIESTI KOLME FULLWIDTH
;; ; % KOLMNEDA PĂRA KOLM
;; ; % KOLME KOLME PUNKT
;; ; % MATEMAACOLILLA BOLD DIGIT KOLM
...
;; ; % KIRILL SILMINE A
;; ; % KIRILL SUUR A
;; ; % KIRILL SILMINE A KĂRGIK
;; ; % KIRILL SILMINE A KĂRGIK
...
;; ; % KIRILL SILMINE BE
;; ; % KIRILL SUUR BE
;; ; % KIRILL SILMINE VE
;; ; % KIRILL SUUR VE
...
tellimus_lĂ”ppNĂŒĂŒd on taas vĂ”imalik naasta artikli alguses esitatud nĂ€idete jĂ€rjestusse. Probleem peitub selles osas kaalu tabelis:
IGNORE;IGNORE;IGNORE; % RUUM
IGNORE;IGNORE;IGNORE; % KĂSIMUSMĂRK
IGNORE;IGNORE;IGNORE; % TSITAAT
...On mĂ€rgata, et selles tabelis ignoreeritakse interpunktsiooni tavaliselt, ASCII (sealhulgas tĂŒhik) stringide vĂ”rdlemisel. Eranditeks on vaid stringid, mis on tĂ€ielikult identsed, vĂ€lja arvatud vastavates positsioonides esinevad interpunktsioonimĂ€rgid. Minu nĂ€ite stringid (pĂ€rast sorteerimist) nĂ€evad vĂ€lja jĂ€rgmiselt:
AbakanovMikhailPainters
YolkinaElenaScreenwriter
IvanovaAllaPainter
IvanovAndreyJoinerArvestades, et kaalutabelis on vene keeles suured tÀhed vÀikeste tÀhtede jÀrel (kolmandal tasemel <CAP> kÔvemad kui <MIN>), siis nÀeb sorteerimine vÀlja tÀiesti korrektne.
Muutes muutuja LC_COLLATE=C laaditakse eriline tabel, mis mÀÀrab byte-taseme 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 asub koodipunkt Рkoha jÀrjekorras A ees, jÀrjestatakse ka stringid vastavalt.
Teksti- ja binaartabelid
On selge, et stringide vĂ”rdlemine on ÀÀrmiselt sage toiming, samas kui tabeli analĂŒĂŒs CTT on ĂŒsna kulukas protseduur. Tabeli juurdepÀÀsu optimeerimiseks kompileeritakse see kahekordsesse vormingusse kĂ€suga localedef.
Meeskond localedef millele antakse parameetritena fail, mis sisaldab riiklike eripĂ€rade tabelit (valik -i), milles kĂ”ik sĂŒmbolid on esitatud Unicode'i punktidena, ja fail, mis seob Unicode'i punkte konkreetse kodeeringu sĂŒmbolitega (valik -f). Töö tulemusena luuakse kohalikuks kaksikfailid, mille nimi on mÀÀratud viimasena antud parameetris.
Glibc toetab kaht tĂŒĂŒpi kahekordse faili formaate: "traditsiooniline" ja "modernne".
Traditsiooniline formaat eeldab, et lokaali nimi on alamkausta nimi /usr/lib/locale/. Selles alamkaustas hoitakse kaksikfailid LC_COLLATE, LC_CTYPE, LC_TIME ja nii edasi. Fail LC_IDENTIFICATION sisaldab lokaali formaalset nime (mis vÔib erineda kausta nimest) ja kommentaare.
Kaasaegne formaat eeldab, et kĂ”ik lokaalid on salvestatud ĂŒhte arhiivi /usr/lib/locale/locale-archive, mis on kaardistatud kĂ”igi protsesside virtuaalsesse mĂ€lu, mis seda kasutavad. glibc. Keelja on kaasaegses formaadis lĂ€bi teinud teatud kanoniseerimise â kodeeringu nimedes jÀÀvad alles vaid numbrid ja tĂ€hed, mis on muudetud vĂ€iketĂ€htedeks. Nii ru_RU.KOI8-R, salvestatakse jĂ€rgmiselt ru_RU.koi8r.
Sisendfailid otsitakse praegusest kataloogist ning ka kataloogidest /usr/share/i18n/locales/ ja /usr/share/i18n/charmaps/ failide CTT ja kodeerimisfailide jaoks vastavalt.
NÀiteks kÀsk
localedef -i ru_RU -f MAC-CYRILLIC ru_RU.MAC-CYRILLICkompileerib faili /usr/share/i18n/locales/ru_RU kasutades kodeerimisfaili /usr/share/i18n/charmaps/MAC-CYRILLIC.gz ja salvestab tulemuse /usr/lib/locale/locale-archive nimega ru_RU.maccyrillic
Kui seadistada muutujaks LANG=en_US.UTF-8 siis glibc otsitakse lokaali binaarfailide jaoks jÀrgmises failide ja kataloogide jÀrjestuses:
/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 traditsioonilises kui ka kaasaegses formaadis, antakse eelis kaasaegsele.
Kompileeritud lokaalide loendit saab vaadata kÀsuga locale -a.
Oma vÔrdlustabeli koostamine
NĂŒĂŒd, relvastatuna teadmistega, on vĂ”imalik luua oma ideaalne stringide vĂ”rdlustabel. See tabel peab Ă”igesti vĂ”rdlema vene tĂ€hti, sealhulgas tĂ€hti Đ, ning arvestama loetlemismĂ€rke vastavalt tabeliga ASCII.
Oma sortimistabeli ettevalmistamise protsess koosneb kahest etapist: kaalutabeli redigeerimisest ja selle kompileerimisest binaarvormis kÀsuga localedef.
Et vÔrdlustabelit oleks vÔimalik kohandada minimaalse redigeerimiskuluga, on formaadis ISO 14652 ette nÀhtud juba olemasoleva tabeli kaalude kohandamise sektsioonid. Sektsioon algab vÔtmesÔnast reorder-after ja positsiooni nÀitamisest, mille jÀrel toimub asendamine. Sektsiooni lÔpetab rida reorder-end. Kui on vaja korrigeerida mitu tabeli osa, luuakse iga sellise osa jaoks oma sektsioon.
Kopeerisin uued versioonid failidest . SeejĂ€rel kaasatakse see fail direktiiviga ja et_RU hoidlast glibc oma kodukatalooge ~/.local/share/i18n/locales/ ja muutsin veidi jaotust LC_COLLATE ĂŒhes et_RU. Uued faili versioonid on tĂ€ielikult ĂŒhilduvad minu versiooniga glibc. Kui soovite kasutada vanu faili versioone, peate muutma sĂŒmboolseid nimesid ja kohta, kust asendamine tabelis algab.
LC_COLLATE
% Kopeeri mall ISO/IEC 14651
kopeerida "iso14651_t1"
jÀrjesta-pÀrast
;;; % TĂŒhi ruum
;;; % Ăksik mĂ€rk
;;; % TsiteerimismÀrk
...
;;; % Parem kurv
;;; % Tilde
jÀrjesta-lÔpp
LĂPP LC_COLLATETegelikult oleks pidanud muutma vĂ€ljad LC_IDENTIFICATION niimoodi, et need viitaksid lokaalile ru_MY, kuid minu nĂ€ites ei olnud see vajalik, kuna ma vĂ€listasin otsingust lokaliseerimise arhiivi locale-archive.
Et localedef töötasin failidega oma kaustas lÀbi muutuja I18NPATH vÔib lisada tÀiendava katalooge sisendfailide otsimiseks, ja katalooge binaarfailide salvestamiseks vÔib mÀÀrata teena, mis sisaldab kaldkriipse:
$> I18NPATH=~/.local/share/i18n localedef -i ru_RU -f UTF-8 ~/.local/lib/locale/ru_MY.UTF-8POSIX eeldab, et LANG vĂ”ib kirjutada absoluutsete teedena kataloogidele, kus asuvad lokaalid, mis algavad otsekaldkriipsuga, kuid glibc ĂŒhes Linux kĂ”ik teed arvestatakse baas-kataloogist, mille vĂ”ib ĂŒletada muutuja LOCPATH. PĂ€rast seadistamist LOCPATH=~/.local/lib/locale/ otsitakse kĂ”iki lokaliseerimisega seotud faile ainult minu kaustast. Lokaalide arhiiv, kui muutuja on seadistatud. LOCPATH ei arvestata.
See test on:
$> LANG=et_EE.UTF-8 LOCPATH=~/.local/lib/locale/ sort buhg.txt
Abakanov Mihhail;vÀrvija
Jolkina Ella;kraanajuht
Ivanov Andrei;sepp
Ivanova Alla;advokaatHurraa! Me tegime selle Àra!
Vigade parandamine
Olen juba vastanud alguses esitatud stringi sortimise kĂŒsimustele, kuid veel on mĂ”ned kĂŒsimused nĂ€htavatest ja nĂ€htamatutest vigadest.
Naaseme algse ĂŒlesande juurde.
Ja programm sort ja programm liitu kasutavad samu stringi vĂ”rdlemise funktsioone glibc. Kuidas juhtus, et liitu andis sortimisvea stringidele, mis sorteeriti kĂ€suga sort jĂ€rgi lokaalis et_US.UTF-8? ĐŃĐČĐ”Ń ĐżŃĐŸŃŃ: sort vĂ”rdleb stringi tervikuna, samas kui liitu vĂ”rdleb ainult vĂ”tit, mis vaikimisi on stringi algus kuni esimese tĂŒhikuni. Minu nĂ€ites viis see veateadeni, kuna lause algusede sortimine ei kattunud tĂ€ielike stringide sortimisega.
Lokaal "C" garanteerib, et sorteeritud ridade algusosad kuni esimese tĂŒhikuni on samuti sorteeritud, kuid see varjab viga. On vĂ”imalik leida selliseid andmeid (inimesed, kellel on sama perekonnanimi, kuid erinevad eesnimed), mis ilma veateateta tooksid vale tulemuse failide ĂŒhinemisel. Kui soovime, et liitu ĂŒhendaks failide ridu FIO jĂ€rgi, siis Ă”ige viis on selgelt mÀÀratleda vĂ€ljade eraldaja ja sorteerida vĂ”tmevĂ€lja jĂ€rgi, mitte kogu rida jĂ€rgi. Sel juhul toimub ĂŒhinemine Ă”igesti ja ei esine vigu ĂŒheski lokaadis:
$> sort -t ; -k 1 buhg.txt > buhg.srt
$> sort -t ; -k 1 mail.txt > mail.srt
$> join -t ; buhg.srt mail.srt > resultEdukalt lĂ€bi viidud nĂ€ide kodeeringus CP1251 sisaldab veel ĂŒhte viga. Asi on selles, et kĂ”igis tuntud distributsioonides Linux puuduvad pakettides kompileeritud lokaalid ru_RU.CP1251. Kui kompileeritud lokaali ei leita, siis sort kasutab vaikselt byte-per-byte vĂ”rdlemist, mida me ka jĂ€lgisime.
Muide, on veel ĂŒks vĂ€ike viga, mis on seotud kompileeritud lokaalide kĂ€ttesaamatusega. KĂ€sk LOCPATH=/tmp locale -a vĂ€ljastab kĂ”ik lokaalid locale-archive, kuid eeldusel, et muutujat on seadistatud LOCPATH kĂ”ikidele programmidele (ka kĂ”igele locale) need lokaalid ei ole 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 comparisonKokkuvÔte
Kui oled programmeerija, kes on harjunud arvama, et stringid on baitide kogum, siis on see sinu valik. LC_COLLATE=C.
Kui oled lingvist vÔi sÔnaraamatute koostaja, siis oleks parem, kui compileeriksid oma lokaali.
Kui oled lihtsalt kasutaja, siis piisab, kui harjuda, et kÀsk ls -a vÀljastab faile, mis algavad punktiga, segatuna failidega, mis algavad tÀhega, ning Midnight Commander, mis kasutab oma sisemisi funktsioone nimede sortimiseks, toob failid, mis algavad punktiga, nimekirja algusesse.
Lingid
Allikas: habr.com
