Linux-en sortak nola ordenatzen dituen kateak

Sarrera

Helbideen informazioa konbinatu behar zuen gidoi labur batekin hasi zen guztia e-posta posta-zerrendako erabiltzaileen zerrendatik lortutako langileak, HR saileko datu-basetik lortutako langile postuekin. Bi zerrendak Unicode testu-fitxategietara esportatu ziren UTF-8 eta Unix lerro amaierarekin gordeta.

edukien mail.txt

Иванов АндрСй;[email protected]

edukien buhg.txt

Иванова Алла;маляр
Ёлкина Π­Π»Π»Π°;ΠΊΡ€Π°Π½ΠΎΠ²Ρ‰ΠΈΡ†Π°
Иванов АндрСй;ΡΠ»Π΅ΡΠ°Ρ€ΡŒ
Абаканов ΠœΠΈΡ…Π°ΠΈΠ»;маляр

Batzeko, fitxategiak Unix komandoaren bidez ordenatu ziren sort eta Unix programaren sarrerara bidali batu, ustekabean huts egin duena errore batekin:

$> sort buhg.txt > buhg.srt
$> sort mail.txt > mail.srt
$> join buhg.srt mail.srt > result
join: buhg.srt:4: is not sorted: Иванов АндрСй;ΡΠ»Π΅ΡΠ°Ρ€ΡŒ

Sailkapenaren emaitza begiekin ikusita, orokorrean sailkapena zuzena dela erakutsi zuen, baina gizonezkoen eta emakumezkoen abizenen kointzidentziaren kasuan, emakumezkoenak gizonezkoen aurretik datoz:

$> sort buhg.txt
Абаканов ΠœΠΈΡ…Π°ΠΈΠ»;маляр
Ёлкина Π­Π»Π»Π°;ΠΊΡ€Π°Π½ΠΎΠ²Ρ‰ΠΈΡ†Π°
Иванова Алла;маляр
Иванов АндрСй;ΡΠ»Π΅ΡΠ°Ρ€ΡŒ

Unicode-n ordenatzeko akats bat edo ordenatzeko algoritmoan feminismoaren agerpen bat dirudi. Lehenengoa, noski, sinesgarriagoa da.

Utz dezagun oraingoz batu eta zentratu sort. Saia gaitezen problema zientifikoa erabiliz konpontzen. Lehenik eta behin, alda dezagun lokalizazioa en_US on ru_RU. Ordenatzeko, nahikoa izango litzateke ingurune-aldagaia ezartzea LC_COLLATE, baina ez dugu denborarik galduko huskeriatan:

$> LANG=ru_RU.UTF-8 sort buhg.txt
Абаканов ΠœΠΈΡ…Π°ΠΈΠ»;маляр
Ёлкина Π­Π»Π»Π°;ΠΊΡ€Π°Π½ΠΎΠ²Ρ‰ΠΈΡ†Π°
Иванова Алла;маляр
Иванов АндрСй;ΡΠ»Π΅ΡΠ°Ρ€ΡŒ

Ez da ezer aldatu.

Saia gaitezen fitxategiak byte bakarreko kodeketa batean birkodetzen:

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

Berriz ere ez da ezer aldatu.

Ezin duzu ezer egin, Interneten irtenbide bat bilatu beharko duzu. Errusiako abizenei buruz ez dago ezer zuzenean, baina beste bitxikeria batzuei buruzko galderak daude. Adibidez, hona hemen arazo bat: unix sortak '-' (marratxoa) karaktereak ikusezin gisa tratatzen ditu. Laburbilduz, "a-b", "aa", "ac" kateak "aa", "a-b", "ac" gisa ordenatzen dira.

Erantzuna estandarra da nonahi: erabili programatzailearen lokalizazioa "C" eta pozik egongo zara. Saia gaitezen:

$> LANG=C sort buhg.txt
Ёлкина Π­Π»Π»Π°;ΠΊΡ€Π°Π½ΠΎΠ²Ρ‰ΠΈΡ†Π°
Абаканов ΠœΠΈΡ…Π°ΠΈΠ»;маляр
Иванов АндрСй;ΡΠ»Π΅ΡΠ°Ρ€ΡŒ
Иванова Алла;Π°Π΄Π²ΠΎΠΊΠ°Ρ‚

Zerbait aldatu da. Ivanovtarrak ordena egokian jarri ziren, nahiz eta Yolkina nonbait irristatu. Itzuli gaitezen jatorrizko arazora:

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

Akatsik gabe funtzionatu zuen, Internetek agindu bezala. Eta hau Yolkina lehen lerroan egon arren.

Arazoa konponduta dagoela dirudi, baina badaezpada, proba dezagun beste kodeketa errusiar bat: Windows CP1251:

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

Sailkapenaren emaitza, bitxia bada ere, lokalarekin bat egingo du "C", eta adibide osoa, horren arabera, akatsik gabe doa. Nolabaiteko mistizismoa.

Ez zait mistizismoa gustatzen programazioan, normalean akatsak ezkutatzen dituelako. Serioski aztertu beharko dugu nola funtzionatzen duen. sort eta zertan eragiten du? LC_COLLATE .

Bukaeran galderei erantzuten saiatuko naiz:

  • zergatik sailkatu ziren emakumezkoen abizenak gaizki?
  • zergatik LANG=ru_RU.CP1251 baliokidea izan zen LANG=C
  • zergatik egin sort ΠΈ batu ordenatutako kateen ordenari buruzko ideia desberdinak
  • zergatik daude akatsak nire adibide guztietan?
  • azkenik, nola ordenatu kateak zure gustura

Unicode-n ordenatzea

Lehenengo geldialdia 10. zenbakiko txosten teknikoa izango da Unicode bilketa algoritmoa online unicode.org. Txostenak xehetasun tekniko asko ditu, beraz, ideia nagusien laburpen labur bat egingo dut.

Collation β€” Β«KonparaketaΒ» kateak edozein ordenatzeko algoritmoaren oinarria da. Algoritmoak eurak desberdinak izan daitezke ("burbuila", "bateratu", "azkar"), baina guztiek kate baten konparaketa erabiliko dute zein ordenatan agertzen diren zehazteko.

Kateak hizkuntza naturalean ordenatzea arazo nahiko konplexua da. Byte bakarreko kodetze sinpleenetan ere, alfabetoko letren ordena, ingeles latindar alfabetotik nolabait desberdina bada ere, ez da bat egingo letra hauek kodetzen diren zenbakizko balioen ordenarekin. Beraz, alemaniar alfabetoan letra Γ– artean dago О ΠΈ P, eta kodetegian CP850 artean sartzen da ΓΏ ΠΈ Ü.

Saia zaitezke kode zehatz batetik abstraitzen eta ordenaren batean antolatutako letra "idealak" kontuan hartu, Unicode-n egiten den bezala. Kodeketak UTF8, UTF16 edo byte batekoa KOI8-R (Unicode azpimultzo mugatu bat behar bada) letren zenbakizko irudikapen desberdinak emango ditu, baina oinarrizko taulako elementu berberak aipatzen ditu.

Gertatzen da ikur-taula hutsetik eraikitzen badugu ere, ezingo diogula sinboloen ordena unibertsala esleitu. Letra berdinak erabiltzen dituzten nazio alfabeto desberdinetan, baliteke letra horien ordena desberdina izatea. Adibidez, frantsesez Γ† ligaturatzat hartuko da eta kate gisa ordenatuta AE. Norvegiaraz Γ† letra bereizi bat izango da, ondoren kokatzen dena Z. Bide batez, bezalako ligatuez gain Γ† Hainbat ikurrekin idatzitako letrak daude. Beraz, Txekiar alfabetoan letra bat dago Ch, tartean dagoena H ΠΈ I.

Alfabetoen desberdintasunez gain, ordenan eragina duten beste tradizio nazional batzuk daude. Bereziki, galdera sortzen da: zer ordenatan agertu behar dira hiztegian letra larriz eta minuskulaz osatutako hitzak? Puntuazio-markak erabiltzeak ere eragina izan dezake ordenatzeak. Gaztelaniaz, galdera-ikurra alderantzikatua erabiltzen da galde-perpausaren hasieran (Musika gustatzen al zaizu?). Kasu honetan, begi-bistakoa da galdera-perpausak ez direla alfabetotik kanpo multzo bereizi batean bildu behar, baina nola ordenatu lerroak beste puntuazio-markekin?

Ez naiz luzatuko kateak Europako hizkuntzetatik oso desberdinak diren hizkuntzatan ordenatzen. Kontuan izan eskuinetik ezkerrera edo goitik beherako idazketa-norabidea duten hizkuntzetan, lerroetako karaktereak ziurrenik irakurketa-ordenan gordetzen direla, eta idazkera ez-alfabetikoko sistemek ere lerroak karakterez karaktere ordenatzeko moduak dituztela. . Adibidez, hieroglifoak estiloaren arabera ordena daitezke (Txinako karaktereen teklak) edo ahoskeraren arabera. Egia esateko, ez dakit emojiak nola antolatu behar diren, baina haientzat ere asmatu dezakezu.

Goian zerrendatutako ezaugarrietan oinarrituta, Unicode tauletan oinarritutako kateak alderatzeko oinarrizko baldintzak formulatu ziren:

  • kateen konparazioa ez da kode taulako karaktereen posizioaren araberakoa;
  • karaktere bakarra osatzen duten karaktereen segidak forma kanonikora murrizten dira (A + goiko zirkulua berdina da Γ…);
  • Kateak alderatzean, karaktere bat katearen testuinguruan hartzen da eta, behar izanez gero, aldamenekoekin konbinatzen da konparazio-unitate batean (Ch txekieraz) edo hainbatetan banatuta dago (Γ† frantsesez);
  • ezaugarri nazional guztiak (alfabetoa, maiuskulak/minuskulak, puntuazioa, idazketa-moten ordena) ordenaren eskuz esleitzeko (emoji) arte konfiguratu behar dira;
  • konparaketa garrantzitsua da ordenatzeko ez ezik, beste leku askotan ere, adibidez, errenkada barrutiak zehazteko ({A... z} ordezkatuz). golpear);
  • konparaketa nahiko azkar egin behar da.

Horrez gain, txostenaren egileek algoritmoen garatzaileek fidatu behar ez dituzten konparazio propietateak formulatu zituzten:

  • Konparazio algoritmoak ez luke hizkuntza bakoitzerako karaktere multzo bereizirik behar (errusiar eta ukrainar hizkuntzek karaktere ziriliko gehienak partekatzen dituzte);
  • konparaketak ez luke Unicode tauletako karaktereen ordenan oinarritu behar;
  • katearen pisuak ez luke katearen atributu bat izan behar, testuinguru kultural ezberdinetan kate berak pisu desberdinak izan ditzakeelako;
  • errenkaden pisuak batu edo zatitzean alda daitezke (tik x < y ez du horri jarraitzen xz < yz);
  • pisu berdinak dituzten kate desberdinak berdintzat hartzen dira ordenazio algoritmoaren ikuspuntutik. Horrelako kateen ordena gehigarria sartzea posible da, baina errendimendua honda dezake;
  • Behin eta berriz ordenatzean, pisu berdina duten errenkadak trukatu daitezke. Sendotasuna ordenatze algoritmo zehatz baten propietatea da, eta ez kateak alderatzeko algoritmo baten propietatea (ikus aurreko paragrafoa);
  • Ordenatzeko arauak denboran zehar alda daitezke kultura-tradizioak hobetu/aldatzen diren heinean.

Halaber, konparazio algoritmoak prozesatzen ari diren kateen semantikaz ezer ez dakiela ezartzen da. Beraz, zifraz soilik osatutako kateak ez dira zenbaki gisa alderatu behar, eta ingelesezko izenen zerrendetan artikulua (Betagarri, The).

Zehaztutako baldintza guztiak betetzeko, maila anitzeko (benetan lau maila) taula ordenatzeko algoritmo bat proposatzen da.

Aurretik, katearen karaktereak forma kanonikora murrizten dira eta konparazio-unitateetan biltzen dira. Konparazio-unitate bakoitzari hainbat pisu esleitzen zaizkio konparazio-maila batzuei dagozkionak. Konparazio-unitateen pisuak multzo ordenatuen elementuak dira (kasu honetan, zenbaki osoak) eta gehiago edo gutxiago alderatu daitezkeenak. Esanahi berezia EZINATUTA (0x0) esan nahi du dagokion konparazio mailan unitate honek ez duela konparazioan parte hartzen. Kateen konparaketa hainbat aldiz errepika daiteke, dagozkien mailen pisuak erabiliz. Maila bakoitzean, bi errenkadetako konparazio-unitateen pisuak elkarren sekuentzialki alderatzen dira.

Tradizio nazional desberdinetarako algoritmoaren inplementazio desberdinetan, koefizienteen balioak desberdinak izan daitezke, baina Unicode estandarrak pisuen oinarrizko taula bat biltzen du - "Unicode-ko elementuen taula lehenetsia" (DUCET). Kontuan izan nahiko nuke aldagaia ezartzea LC_COLLATE kateen konparazio-funtzioan pisu-taularen hautaketaren adierazle da.

Ponderazio-koefizienteak DUCET honela antolatuta:

  • lehen mailan, letra guztiak kasu berdinera murrizten dira, diakritikoak baztertzen dira, puntuazio markak (ez guztiak) alde batera uzten dira;
  • bigarren mailan, diakritikoak bakarrik hartzen dira kontuan;
  • hirugarren mailan, kasu bakarra hartzen da kontuan;
  • laugarren mailan, puntuazio-markak bakarrik hartzen dira kontuan.

Konparaketa hainbat pasetan egiten da: lehenik eta behin, lehen mailako koefizienteak alderatzen dira; pisuak bat datoz gero, bigarren mailako pisuekin konparaketa errepikatua egiten da; gero agian hirugarren bat eta laugarren bat.

Konparazioa errenkadak pisu ezberdinekin bat datozen konparazio-unitateak dituztenean amaitzen da. Lau mailatan pisu berdina duten errenkadak elkarren berdintzat hartzen dira.

Algoritmo honek (xehetasun tekniko osagarri ugarirekin) izena eman zion 10. zenbakiaren txostenari - "Unicode bilketa algoritmoa" (ACU).

Hona hemen gure adibidetik ordenatzeko portaera apur bat argiago. Polita litzateke Unicode estandarrekin alderatzea.

Inplementazioak probatzeko ACU berezi bat dago test, erabiliz pisuen fitxategia, gauzatzen DUCET. Balantza fitxategian era guztietako gauza dibertigarriak aurki ditzakezu. Adibidez, mahjong eta Europako dominoen ordena dago, baita karta sorta bateko paloen ordena ere (ikurra 1F000 eta aurrerago). Karta-paloak zubiaren arauen arabera jartzen dira - PCBT, eta paloko kartak T, 2,3, XNUMX... K sekuentzian daude.

Errenkadak ondo ordenatuta daudela eskuz egiaztatzea DUCET nahiko neketsua izango litzateke, baina, zorionez, Unicoderekin lan egiteko liburutegiaren inplementazio eredugarri bat dago - "Unicoderako nazioarteko osagaiak"(ZIU).

Liburutegi honen webgunean, urtean garatua IBM, demo orriak daude, besteak beste kateak alderatzeko algoritmoaren orria. Gure proba-lerroak ezarpen lehenetsiekin sartzen ditugu eta, hara, errusiar sailkapen perfektua lortzen dugu.

Абаканов ΠœΠΈΡ…Π°ΠΈΠ»;маляр
Ёлкина Π­Π»Π»Π°;ΠΊΡ€Π°Π½ΠΎΠ²Ρ‰ΠΈΡ†Π°
Иванов АндрСй;ΡΠ»Π΅ΡΠ°Ρ€ΡŒ
Иванова Алла;Π°Π΄Π²ΠΎΠΊΠ°Ρ‚

Bide batez, webgunea ZIU Puntuazio-markak prozesatzen dituzunean konparazio-algoritmoaren argipena aurki dezakezu. Adibideetan Bilduren ohiko galderak apostrofoa eta marratxoa ez dira aintzat hartzen.

Unicodek lagundu zigun, baina portaera arraroen arrazoiak bilatu sort Π² Linux beste norabait joan beharko du.

Glibc-en ordenatzen

Erabilgarritasun iturri-kodeen ikuspegi azkarra sort - GNU Core Utils erakutsi zuen erabilgarritasunean bertan lokalizazioa aldagaiaren uneko balioa inprimatzera datorrela LC_COLLATE arazketa moduan exekutatzen denean:

$ sort --debug buhg.txt > buhg.srt
sort: using β€˜en_US.UTF8’ sorting rules

Kateen konparaketak funtzio estandarra erabiliz egiten dira strcoll, hau da, interesgarria dena liburutegian dagoela esan nahi du glibc.

On wiki proiektua glibc kateen konparazioari eskainia paragrafo bat. Paragrafo honetatik uler daitekeela glibc ordenatzea dagoeneko ezagutzen dugun algoritmo batean oinarritzen da ACU (Unicode bilketa algoritmoa) eta/edo hurbileko estandar batean ISO 14651 (Nazioarteko kateen ordena eta konparazioa). Azken estandarrari dagokionez, kontuan izan behar da gunean estandarrak.iso.org ISO 14651 ofizialki publikoki eskuragarri deklaratu da, baina dagokion estekak existitzen ez den orri batera eramaten du. Google-k hainbat orrialde itzultzen ditu estandarraren kopia elektronikoa ehun euroren truke erostea eskaintzen duten gune ofizialetarako estekekin, baina bilaketa-emaitzen hirugarren edo laugarren orrialdean esteka zuzenak ere badaude. PDF. Oro har, estandarra ez da ia desberdina ACU, baina irakurtzea aspergarriagoa da, ez baitakar kateen ordenazioaren ezaugarri nazionalen adibide argirik.

Informaziorik interesgarriena wiki lotura bat zegoen akatsen jarraipena kateen konparazioaren ezarpenari buruzko eztabaidarekin glibc. Eztabaidatik hori ikas daiteke glibc kateak alderatzeko erabiltzen da ISOmahai pertsonala Txantiloi Taula Komuna (CTT), zeinaren helbidea eskabidean aurki daiteke A estandarra ISO 14651. 2000. eta 2015. urteen artean taula hau glibc ez zuen mantentzailerik eta nahiko desberdina zen (kanpotik behintzat) estandarraren egungo bertsiotik. 2015etik 2018ra, taularen bertsio berrirako egokitzapena egin zen, eta orain bizitza errealean mahaiaren bertsio berri bat ezagutzeko aukera duzu (CentOS 8), eta zaharra (CentOS 7).

Algoritmoari eta taula laguntzaileei buruzko informazio guztia daukagunez, jatorrizko arazora itzuli eta kateak nola ordenatu behar diren uler dezakegu errusiar lokalean.

ISO 14651 / 14652

Interesatzen zaigun taularen iturburu kodea CTT banaketa gehienetan Linux katalogoan dago /usr/share/i18n/locales/. Taula bera fitxategian dago iso14651_t1_ohikoa. Ondoren, hau da fitxategien zuzentaraua kopiatu iso14651_t1_common fitxategian sartuta iso14651_t1, zeina, berriz, espediente nazionaletan sartzen dena, barne en_US ΠΈ ru_RU. Banaketa gehienetan Linux iturburu-fitxategi guztiak oinarrizko instalazioan sartzen dira, baina ez badaude, banaketako pakete gehigarri bat instalatu beharko duzu.

Fitxategien egitura iso14651_t1 Izugarrizko hitza dirudi, izenak eraikitzeko arau ez-nabarmenekin, baina begiratuz gero, dena nahiko sinplea da. Egitura estandarrean deskribatzen da ISO 14652, horren kopia bat webgunetik deskargatu daiteke open-std.org. Fitxategi-formatuaren beste deskribapen bat irakur daiteke zehaztapenak POSIX tik OpenGroup. Estandarra irakurtzearen alternatiba gisa, funtzioaren iturburu-kodea azter dezakezu bildu_irakur Π² glibc/locale/programs/ld-collate.c.

Fitxategiaren egiturak itxura hau du:

Lehenespenez, karakterea ihes karaktere gisa erabiltzen da, eta # karakterearen ondorengo lerroaren amaiera iruzkin bat da. Ikur biak birdefinitu daitezke, hau da, taularen bertsio berrian egiten dena:

escape_char /
comment_char %

Fitxategiak tokenak izango ditu formatuan edo (Non x - zifra hamaseitarra). Hau kodeko Unicode kode puntuen hamaseitarra da UCS-4 (UTF-32). Beste elementu guztiak parentesi angeluetan (barne , <2> eta antzekoak) testuingurutik kanpo esanahi gutxi duten kate-konstante soiltzat hartzen dira.

ilara LC_COLLATE esaten digu hurrengoan hasten direla kateen konparaketa deskribatzen duten datuak.

Lehenik eta behin, konparazio-taulan pisuetarako izenak eta sinboloen konbinazioetarako izenak zehazten dira. Oro har, bi izen motak bi entitate ezberdinetakoak dira, baina benetako fitxategian nahasten dira. Pisuen izenak gako-hitzarekin zehazten dira elkarketa-sinbolo (konparazio karakterea) zeren alderatzean, pisu berdina duten Unicode karaktereak karaktere baliokidetzat hartuko dira.

Uneko fitxategi berrikuspenean atalaren luzera guztira 900 lerro ingurukoa da. Hainbat lekutako adibideak atera ditut izenen arbitrariotasuna eta hainbat sintaxi mota erakusteko.

LC_COLLATE

collating-symbol <RES-1>
collating-symbol <BLK>
collating-symbol <MIN>
collating-symbol <WIDE>
...
collating-symbol <ARABIC>
collating-symbol <ETHPC>
collating-symbol <OSMANYA>
...
collating-symbol <S1D000>..<S1D35F>
collating-symbol <SFFFF> % Guaranteed largest symbol value. Keep at end of this list
...
collating-element <U0413_0301> from "<U0413><U0301>"
collating-element <U0413_0341> from "<U0413><U0341>"

  • collating-sinboloa kate bat erregistratzen du OSMANYA eskalen izenen taulan
  • elkarketa-sinboloa .. aurrizki batez osatutako izen-segida erregistratzen du S eta zenbakizko atzizki hamaseitarra from 1D000 to 1D35F.
  • FFFF Π² collating-sinboloa sinatu gabeko zenbaki oso handi baten itxura du hamaseitarraz, baina itxura izan dezakeen izena besterik ez da
  • izena kode-puntua esan nahi du UCS-4
  • ""-tik elementu-bilketa Unicode puntu pare baten izen berri bat erregistratzen du.

Pisuen izenak zehaztu ondoren, benetako pisuak zehazten dira. Erlazio handiagoak baino gutxiago baino ez dutenez konparazioan, pisuak zerrenda-izenen sekuentzia soil batek zehazten ditu. Pisu "arinenak" zerrendatzen dira lehenik, gero "astunenak". Gogorarazten dizut Unicode karaktere bakoitzari lau pisu ezberdin esleitzen zaizkiola. Hemen sekuentzia ordenatu bakar batean konbinatzen dira. Teorian, edozein izen sinboliko erabil liteke lau mailetako edozeinetan, baina iruzkinek adierazten dute garatzaileek mentalki izenak mailatan bereizten dituztela.

% Symbolic weight assignments

% Third-level weight assignments
<RES-1>
<BLK>
<MIN>
<WIDE>
...
% Second-level weight assignments
<BASE>
<LOWLINE> % COMBINING LOW LINE
<PSILI> % COMBINING COMMA ABOVE
<DASIA> % COMBINING REVERSED COMMA ABOVE
...
% First-level weight assignments
<S0009> % HORIZONTAL TABULATION 
<S000A> % LINE FEED
<S000B> % VERTICAL TABULATION
...
<S0434> % CYRILLIC SMALL LETTER DE
<S0501> % CYRILLIC SMALL LETTER KOMI DE
<S0452> % CYRILLIC SMALL LETTER DJE
<S0503> % CYRILLIC SMALL LETTER KOMI DJE
<S0453> % CYRILLIC SMALL LETTER GJE
<S0499> % CYRILLIC SMALL LETTER ZE WITH DESCENDER
<S0435> % CYRILLIC SMALL LETTER IE
<S04D7> % CYRILLIC SMALL LETTER IE WITH BREVE
<S0454> % CYRILLIC SMALL LETTER UKRAINIAN IE
<S0436> % CYRILLIC SMALL LETTER ZHE

Azkenik, benetako pisuaren taula.

Pisuen atala gako-lerroetan dago ordena_hasi ΠΈ ordena_amaiera. Aukera gehigarriak ordena_hasi zehaztea zein norabidetan eskaneatzen diren errenkadak konparazio-maila bakoitzean. Ezarpen lehenetsia da aurrera. Atalaren gorputza sinboloaren kodea eta bere lau pisuak dituzten lerroz osatuta dago. Karaktere-kodea karaktereak berak, kode-puntu batek edo aurretik definitutako izen sinboliko batek irudika dezake. Izen sinbolikoei, kode puntuei edo sinboloei beraiei ere eman dakieke pisuak. Kode puntuak edo karaktereak erabiltzen badira, haien pisua kode puntuaren zenbakizko balioaren berdina da (posizioa Unicode taulan). Esplizituki zehaztu ez diren karaktereak (ulertzen dudanez) taulari esleituta daude Unicode taulako posizioarekin bat datorren pisu nagusi batekin. Pisu-balio berezia EZKUTATU esan nahi du ikurra alde batera uzten dela konparazio maila egokian.

Eskalen egitura erakusteko, hiru zati nahiko agerikoak aukeratu ditut:

  • erabat baztertzen diren pertsonaiak
  • lehenengo bi mailetan hiru zenbakiaren baliokideak diren sinboloak
  • alfabeto zirilikoaren hasiera, diakritikorik ez duena, eta, beraz, batez ere lehen eta hirugarren mailetan ordenatuta dago.

order_start forward;forward;forward;forward,position
<U0000> IGNORE;IGNORE;IGNORE;IGNORE % NULL (in 6429)
<U0001> IGNORE;IGNORE;IGNORE;IGNORE % START OF HEADING (in 6429)
<U0002> IGNORE;IGNORE;IGNORE;IGNORE % START OF TEXT (in 6429)
...
<U0033> <S0033>;<BASE>;<MIN>;<U0033> % DIGIT THREE
<UFF13> <S0033>;<BASE>;<WIDE>;<UFF13> % FULLWIDTH DIGIT THREE
<U2476> <S0033>;<BASE>;<COMPAT>;<U2476> % PARENTHESIZED DIGIT THREE
<U248A> <S0033>;<BASE>;<COMPAT>;<U248A> % DIGIT THREE FULL STOP
<U1D7D1> <S0033>;<BASE>;<FONT>;<U1D7D1> % MATHEMATICAL BOLD DIGIT THREE
...
<U0430> <S0430>;<BASE>;<MIN>;<U0430> % CYRILLIC SMALL LETTER A
<U0410> <S0430>;<BASE>;<CAP>;<U0410> % CYRILLIC CAPITAL LETTER A
<U04D1> <S04D1>;<BASE>;<MIN>;<U04D1> % CYRILLIC SMALL LETTER A WITH BREVE
<U0430_0306> <S04D1>;<BASE>;<MIN>;<U04D1> % CYRILLIC SMALL LETTER A WITH BREVE
...
<U0431> <S0431>;<BASE>;<MIN>;<U0431> % CYRILLIC SMALL LETTER BE
<U0411> <S0431>;<BASE>;<CAP>;<U0411> % CYRILLIC CAPITAL LETTER BE
<U0432> <S0432>;<BASE>;<MIN>;<U0432> % CYRILLIC SMALL LETTER VE
<U0412> <S0432>;<BASE>;<CAP>;<U0412> % CYRILLIC CAPITAL LETTER VE
...
order_end

Orain artikuluaren hasieratik adibideak ordenatzera itzul zaitezke. Segada pisuen taularen zati honetan dago:

<U0020> IGNORE;IGNORE;IGNORE;<U0020> % SPACE
<U0021> IGNORE;IGNORE;IGNORE;<U0021> % EXCLAMATION MARK
<U0022> IGNORE;IGNORE;IGNORE;<U0022> % QUOTATION MARK
...

Ikus daiteke taula honetan taulako puntuazio markak direla ASCII (espazioa barne) kateak alderatzean ia beti baztertzen da. Salbuespen bakarrak bat datozen posizioetan aurkitutako puntuazio-markak izan ezik denetan bat datozen lerroak dira. Nire adibideko lerroek (ordenatu ondoren) konparazio algoritmoaren itxura dute:

ΠΠ±Π°ΠΊΠ°Π½ΠΎΠ²ΠœΠΈΡ…Π°ΠΈΠ»ΠΌΠ°Π»ΡΡ€
ЁлкинаЭллакрановщица
Π˜Π²Π°Π½ΠΎΠ²Π°ΠΠ»Π»Π°ΠΌΠ°Π»ΡΡ€
Π˜Π²Π°Π½ΠΎΠ²ΠΠ½Π΄Ρ€Π΅ΠΉΡΠ»Π΅ΡΠ°Ρ€ΡŒ

Kontuan izanda eskalen taulan, errusierazko letra larriak minuskularen ondoren datozela (hirugarren mailan baino astunagoa ), ordenatzeak guztiz zuzena dirudi.

Aldagai bat ezartzerakoan LC_COLLATE=C bytez byte alderaketa zehazten duen taula berezi bat kargatzen da

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'xfe', L'xff'
};

Unicode-n Ё kode-puntua A aurretik dagoenez, kateak horren arabera ordenatzen dira.

Testu eta bitako taulak

Jakina, kateen konparazioa oso ohikoa da eragiketa eta taularen analisia CTT prozedura nahiko garestia. Taularako sarbidea optimizatzeko, forma bitar batean konpilatzen da komandoarekin lokaldef.

Team lokaldef parametro gisa nazio-ezaugarrien taula duen fitxategi bat onartzen du (aukera -i), zeinetan karaktere guztiak Unicode puntuen bidez adierazten diren, eta Unicode puntuen eta kodeketa zehatz bateko karaktereen arteko korrespondentzia fitxategi bat (aukera -f). Lanaren ondorioz, lokalerako fitxategi bitarrak sortzen dira azken parametroan zehaztutako izenarekin.

glibc Bi fitxategi formatu bitar onartzen ditu: "tradizionala" eta "modernoa".

Formatu tradizionalak esan nahi du lokalaren izena barruko azpidirektorioaren izena dela /usr/lib/locale/. Azpidirektorio honek fitxategi bitarrak gordetzen ditu LC_COLLATE, LC_CTYPE, LC_TIME eta abar. Fitxategia LC_IDENTIFIKAZIOA lokalaren izen formala (direktorioaren izenetik desberdina izan daitekeena) eta iruzkinak ditu.

Formatu modernoak lokal guztiak artxibo bakarrean gordetzea dakar /usr/lib/locale/locale-archive, erabiltzen diren prozesu guztien memoria birtualean mapatzen dena glibc. Formatu modernoko lokalaren izena kanonizazio baten menpe dago; letra xeheetara murriztutako zenbakiak eta letrak bakarrik geratzen dira kodeketa-izenetan. Beraz ru_RU.KOI8-R, honela gordeko da ru_RU.koi8r.

Sarrerako fitxategiak uneko direktorioan bilatzen dira, baita direktorioetan ere /usr/share/i18n/locales/ ΠΈ /usr/share/i18n/charmaps/ fitxategietarako CTT eta kodetzeko fitxategiak, hurrenez hurren.

Adibidez, komandoa

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

fitxategia konpilatuko du /usr/share/i18n/locales/ru_RU kodetze fitxategia erabiliz /usr/share/i18n/charmaps/MAC-CYRILLIC.gz eta gorde emaitza /usr/lib/locale/locale-archive izenpean ru_RU.maccyrillic

Aldagaia ezartzen baduzu LANG = en_US.UTF-8 dela glibc lokaleko bitarrak bilatuko ditu fitxategi eta direktorioen sekuentzia honetan:

/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/

Lokal bat formatu tradizionalean zein modernoan gertatzen bada, orduan lehentasuna modernoari emango zaio.

Komandoarekin konpilatutako lokalen zerrenda ikus dezakezu locale -a.

Zure konparazio taula prestatzen

Orain, ezagutzaz armatuta, zure kateen konparazio taula ideala sor dezakezu. Taula honek errusiar letrak ondo alderatu behar ditu, Ё letra barne, eta, aldi berean, puntuazio-markak kontuan hartu behar ditu taularen arabera. ASCII.

Zure ordenatzeko taula prestatzeko prozesuak bi fase ditu: pisuen taula editatzea eta forma bitar batean konpilatzea komandoarekin. lokaldef.

Konparazio taula muntaketa kostu minimoekin doitzeko, formatuan ISO 14652 Lehendik dagoen taula baten pisuak doitzeko atalak eskaintzen dira. Atala gako-hitz batekin hasten da berrantolatu-ondoren eta ordezkapena egin ondoren zein posizioa adieraziz. Atala lerroarekin amaitzen da birordenatu-amaiera. Taularen hainbat atal zuzendu behar badira, atal bakoitzeko atal bat sortzen da.

Fitxategien bertsio berriak kopiatu ditut iso14651_t1_ohikoa ΠΈ ru_RU biltegitik glibc Nire etxeko direktoriora ~/.local/share/i18n/locales/ eta pixka bat editatu atala LC_COLLATE Π² ru_RU. Fitxategien bertsio berriak guztiz bateragarriak dira nire bertsioarekin glibc. Fitxategien bertsio zaharragoak erabili nahi badituzu, izen sinbolikoak eta ordezkapena hasten den lekua aldatu beharko dituzu taulan.

LC_COLLATE
% Copy the template from ISO/IEC 14651
copy "iso14651_t1"
reorder-after <U000D>
<U0020> <S0020>;<BASE>;<MIN>;<U0020> % SPACE
<U0021> <S0021>;<BASE>;<MIN>;<U0021> % EXCLAMATION MARK
<U0022> <S0022>;<BASE>;<MIN>;<U0022> % QUOTATION MARK
...
<U007D> <S007D>;<BASE>;<MIN>;<U007D> % RIGHT CURLY BRACKET
<U007E> <S007E>;<BASE>;<MIN>;<U007E> % TILDE
reorder-end
END LC_COLLATE

Izan ere, beharrezkoa izango litzateke eremuak aldatzea LC_IDENTIFIKAZIOA lokalera seinalatu dezaten ru_NIRE, baina nire adibidean hori ez zen beharrezkoa, lokalen bilaketatik artxiboa baztertu nuen eta lokala-artxiboa.

That lokaldef aldagai baten bidez nire karpetako fitxategiekin lan egin nuen I18NBIDEA Direktorio gehigarri bat gehi dezakezu sarrerako fitxategiak bilatzeko, eta bitar fitxategiak gordetzeko direktorioa barra-barradun bide gisa zehaztu daiteke:

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

POSIX urtean hori suposatzen du BAKARRIK tokiko fitxategiekin direktorioetarako bide absolutuak idatz ditzakezu, barra barra batekin hasita, baina glibc Π² Linux bide guztiak oinarrizko direktoriotik zenbatzen dira, aldagai baten bidez gainidatzi daitekeena LOCPATH. Instalatu ondoren LOCPATH=~/.local/lib/locale/ Lokalizazioarekin lotutako fitxategi guztiak nire karpetan bakarrik bilatuko dira. Aldagai multzoa duten lokalen artxiboa LOCPATH baztertu.

Hona hemen proba erabakigarria:

$> LANG=ru_MY.UTF-8 LOCPATH=~/.local/lib/locale/ sort buhg.txt
Абаканов ΠœΠΈΡ…Π°ΠΈΠ»;маляр
Ёлкина Π­Π»Π»Π°;ΠΊΡ€Π°Π½ΠΎΠ²Ρ‰ΠΈΡ†Π°
Иванов АндрСй;ΡΠ»Π΅ΡΠ°Ρ€ΡŒ
Иванова Алла;Π°Π΄Π²ΠΎΠΊΠ°Ρ‚

Aupa! Egin dugu!

Akats batzuk

Dagoeneko erantzun ditut hasieran planteatutako kateen ordenazioari buruzko galderak, baina oraindik akatsei buruzko galdera pare bat daude: ikusgaiak eta ikusezinak.

Itzuli gaitezen jatorrizko arazora.

Eta programa sort eta programa batu erabili kateen konparazio funtzio berdinak glibc. Nola gertatu zen hori batu komandoaren arabera ordenatutako errenkadetan ordenatzeko errore bat eman du sort lokalean eu_US.UTF-8? Erantzuna erraza da: sort kate osoa konparatzen du, eta batu gakoa bakarrik konparatzen du, lehenespenez katearen hasiera den lehen zuriuneko karaktereraino. Nire adibidean, horrek errore-mezu bat eragin zuen, lerroetako lehen hitzen ordena ez zetorrelako lerro osoen ordenarekin bat.

Tokikoa "C" ordenatutako kateetan hasierako azpikateak lehen espazioraino ere ordenatuko direla bermatzen du, baina honek errorea ezkutatzen du. Errore-mezurik gabe fitxategi bateratze-emaitza okerra emango luketen datuak (abizen berdinak, baina izen desberdinak dituztenak) hauta daitezke. Nahi badugu batu batutako fitxategi-lerroak izen osoz, orduan modu zuzena eremu-bereizlea esplizituki zehaztea eta gako-eremuaren arabera ordenatzea izango litzateke, eta ez lerro osoaren arabera. Kasu honetan, bateratzea behar bezala egingo da eta ez da akatsik egongo inongo lokaletan:

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

Arrakastaz exekutatutako adibidea kodetegian CP1251 beste errore bat dauka. Kontua da ezagutzen ditudan banaketa guztietan Linux paketeei konpilatutako lokala falta zaie ru_RU.CP1251. Konpilatutako lokalizazioa ez bada aurkitzen, orduan sort isilean bytez byte konparaketa bat erabiltzen du, horixe da behatu duguna.

Bide batez, konpilatutako lokalen eskuraezintasunari lotutako beste arazo txiki bat dago. Taldea LOCPATH=/tmp lokalizazioa -a toki guztien zerrenda emango du lokala-artxiboa, baina aldagai multzoarekin LOCPATH programa guztietarako (gehienak barne locale) lokal hauek ez dira erabilgarri egongo.

$> 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

Ondorioa

Kateak byte multzo bat direla pentsatzera ohituta dagoen programatzailea bazara, orduan zure aukera LC_COLLATE=C.

Hizkuntzalaria edo hiztegi-konpilatzailea bazara, hobe duzu zure lokalean konpilatzea.

Erabiltzaile soila bazara, komandoa horretara ohitu besterik ez duzu behar ls -a puntu batez hasten diren fitxategiak ateratzen ditu letraz hasten diren fitxategiekin nahastuta, eta Gauerdiko komandantea, izenak ordenatzeko barne funtzioak erabiltzen dituenak, zerrendaren hasieran puntu batekin hasten diren fitxategiak jartzen ditu.

Erreferentziak

10. txostena Unicode bilketa algoritmoa

Karaktereen pisuak unicode.org webgunean

ZIU β€” IBMren Unicoderekin lan egiteko liburutegi baten ezarpena.

Ordenatzeko proba erabiliz ZIU

Pertsonaien pisuak barne ISO 14651

Fitxategi-formatuaren deskribapena eskalekin ISO 14652

Kateen konparazioaren inguruko eztabaida glibc

Iturria: www.habr.com

Gehitu iruzkin berria