{"id":83055,"date":"2020-05-28T01:42:15","date_gmt":"2020-05-27T23:42:15","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki"},"modified":"2020-05-28T01:42:15","modified_gmt":"2020-05-27T23:42:15","slug":"kak-linuxovskij-sort-sortiruet-stroki","status":"publish","type":"post","link":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki","title":{"rendered":"Hoe de Linux sort-functie rijen sorteert.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h1 id=\"vvedenie\">Inleiding<\/h1>\n<p><\/p>\n<p>Alles begon met een kort script dat de informatie over adressen moest combineren <em>e-mail<\/em> van medewerkers, verkregen uit de lijst van gebruikers van de mailinglijst, met de functies van medewerkers, verkregen uit de HR-database. Beide lijsten zijn ge\u00ebxporteerd naar tekstbestanden in Unicode-encoding <em>UTF-8<\/em> en opgeslagen met Unix-eindes.<\/p>\n<p><\/p>\n<p>Inhoud <em>mail.txt<\/em><\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Ivanov Andrey;ia@example.com<\/code><\/pre>\n<p><\/p>\n<p>Inhoud <em>buhg.txt<\/em><\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Ivanova Alla;schilder\nYelkina Ella;kraanmachinist\nIvanov Andrey;loodgieter\nAbakanov Mikhail;schilder<\/code><\/pre>\n<p><\/p>\n<p>Om de bestanden te combineren, werden ze gesorteerd met het Unix-commando <em>sort<\/em> en doorgegeven aan het Unix-programma <em>join<\/em>, dat onverwacht eindigde met een foutmelding: <\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; sort buhg.txt &gt; buhg.srt\n$&gt; sort mail.txt &gt; mail.srt\n$&gt; join buhg.srt mail.srt &gt; result\njoin: buhg.srt:4: is not sorted: Ivanov Andrey;loodgieter<\/code><\/pre>\n<p><\/p>\n<p>Het bekijken van het sorteeresultaat gaf aan dat de sortering over het algemeen correct was, maar in het geval van overeenkomsten tussen mannelijke en vrouwelijke achternamen, zijn de vrouwelijke eerst:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; sort buhg.txt\nAbakanov Mikhail;schilder\nYelkina Ella;kraanmachinist\nIvanova Alla;schilder\nIvanov Andrey;loodgieter<\/code><\/pre>\n<p><\/p>\n<p>Het lijkt op een fout in de sortering in Unicode of op een uiting van feminisme in het sorteeralgoritme. Het eerste lijkt natuurlijk plausibeler.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Laten we het voor nu uitstellen <em>join<\/em> en ons concentreren op <em>sort<\/em>. Laten we proberen het probleem op de proef te stellen. Laten we beginnen met het wijzigen van de locatie naar <em>en_US<\/em> en een werkende opdracht krijgen. <em>ru_RU<\/em>. Voor het sorteren zou het voldoende zijn om de omgevingsvariabele <em>LC_COLLATE<\/em>, in te stellen, maar we willen het niet zo kleinziend maken:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LANG=ru_RU.UTF-8 sort buhg.txt\nAbakanov Mikhail;schilder\nYelkina Ella;kraanmachinist\nIvanova Alla;schilder\nIvanov Andrey;loodgieter<\/code><\/pre>\n<p><\/p>\n<p>Er is niets veranderd.<\/p>\n<p><\/p>\n<p>Laten we proberen de bestanden naar een eencodering te converteren: <\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; iconv -f UTF-8 -t KOI8-R buhg.txt \n | LANG=ru_RU.KOI8-R sort \n | iconv -f KOI8-R -t UTF8<\/code><\/pre>\n<p><\/p>\n<p>Weer is er niets veranderd.<\/p>\n<p><\/p>\n<p>We hebben geen andere keuze dan een oplossing op internet te zoeken. Direct over Russische achternamen is niets te vinden, maar er zijn vragen over andere vreemde sorteringen. Hier is bijvoorbeeld zo'n probleem: <noindex><a rel=\"nofollow\" href=\"https:\/\/serverfault.com\/questions\/95579\/unix-sort-treats-dash-characters-as-invisible\/95593\">Unix sort beschouwt &#8216;-&#8216; (streepje) als onzichtbare karakters<\/a><\/noindex>. Kort gezegd, worden de regels &quot;a-b&quot;, &quot;aa&quot;, &quot;ac&quot; gesorteerd als &quot;aa&quot;, &quot;a-b&quot;, &quot;ac&quot;.<\/p>\n<p><\/p>\n<p>Het antwoord is overal standaard: gebruik de programmeertaal-locatie <em>&quot;C&quot;<\/em> en je hebt geluk. Laten we het proberen:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LANG=C sort buhg.txt\nYelkina Ella;kraanmachinist\nAbakanov Mikhail;schilder\nIvanov Andrey;loodgieter\nIvanova Alla;advocaat<\/code><\/pre>\n<p><\/p>\n<p>Er is iets veranderd. De Ivanovs staan nu in de juiste volgorde, maar Yelkina is ergens naartoe geslopen. Laten we teruggaan naar de oorspronkelijke taak:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LANG=C sort buhg.txt &gt; buhg.srt\n$&gt; LANG=C sort mail.txt &gt; mail.srt\n$&gt; LANG=C join buhg.srt mail.srt &gt; result<\/code><\/pre>\n<p><\/p>\n<p>Het werkte zonder fouten, zoals het internet beloofde. En dat ondanks de \u0401lkin op de eerste regel.<\/p>\n<p><\/p>\n<p>Het probleem lijkt opgelost, maar voor de zekerheid proberen we nog een Russische codering \u2014 de Windows-codering. <em>CP1251<\/em>:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; iconv -f UTF-8 -t CP1251 buhg.txt \n | LANG=ru_RU.CP1251 sort \n | iconv -f CP1251 -t UTF8 <\/code><\/pre>\n<p><\/p>\n<p>Het sorteers resultaat zal, vreemd genoeg, overeenkomen met de locale. <em>&quot;C&quot;<\/em>, en het hele voorbeeld passeert dus zonder fouten. Het is een soort mystiek.<\/p>\n<p><\/p>\n<p>Ik hou niet van mystiek in programmeren, omdat het meestal fouten verbergt. Ik moet serieus kijken naar hoe het werkt <em>sort<\/em> en op wat het invloed heeft. <em>LC_COLLATE<\/em> .<\/p>\n<p><\/p>\n<p>Aan het einde zal ik proberen de vragen te beantwoorden:<\/p>\n<p><\/p>\n<ul>\n<li>waarom de vrouwelijke achternamen niet goed gesorteerd waren.<\/li>\n<li>waarom <em>LANG=ru_RU.CP1251<\/em> bleek equivalent te zijn aan <em>LANG=C<\/em><\/li>\n<li>waarom <em>sort<\/em> en <em>join<\/em> verschillende opvattingen over de volgorde van gesorteerde regels hebben.<\/li>\n<li>waarom er in al mijn voorbeelden fouten zitten.<\/li>\n<li>en tot slot, hoe je regels naar eigen smaak kunt sorteren.<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"sortirovka-v-yunikode\">Sorteren in Unicode.<\/h1>\n<p><\/p>\n<p>De eerste stop is het technische rapport nr. 10 met de titel <noindex><a rel=\"nofollow\" href=\"https:\/\/unicode.org\/reports\/tr10\/\">Unicode collation algorithm.<\/a><\/noindex> op de website <noindex><a rel=\"nofollow\" href=\"https:\/\/unicode.org\">unicode.org<\/a><\/noindex>. Het rapport bevat veel technische details, dus ik sta mezelf toe een samenvatting van de belangrijkste idee\u00ebn te geven.<\/p>\n<p><\/p>\n<p><em>Collatie<\/em> \u2014 &quot;vergelijking&quot; van regels is de basis van elk sorteeralgoritme. De algoritmen kunnen verschillen (&quot;bubbel&quot;, &quot;samensmelten&quot;, &quot;snelle&quot;), maar allemaal zullen ze paren van regels vergelijken om de volgorde te bepalen.<\/p>\n<p><\/p>\n<p>Het sorteren van regels in natuurlijke taal is een behoorlijk complexe zaak. Zelfs in de eenvoudigste eencoderingen zal de volgorde van de letters in een alfabet, dat op de een of andere manier verschilt van het Engelse alfabet, niet overeenkomen met de numerieke waarden waarmee die letters gecodeerd zijn. Zo staat in het Duitse alfabet de letter <em>\u00d6<\/em> tussen <em>groot aantal partitions.<\/em> en <em>P<\/em>, maar in de codering <em>CP850<\/em> valt het tussen <em>\u00ff<\/em> en <em>\u00dc.<\/em>.<\/p>\n<p><\/p>\n<p>We kunnen proberen ons los te maken van de specifieke codering en de &quot;ideale&quot; letters beschouwen, die in een bepaalde volgorde zijn geplaatst, zoals dat in Unicode is gedaan. Coderingen <em>UTF8<\/em>, <em>UTF16<\/em> of eencodering <em>KOI8-R<\/em> (als een beperkte subset van Unicode nodig is) zullen verschillende numerieke representaties van letters geven, maar verwijzen tegelijkertijd naar dezelfde basis tabel elementen. <\/p>\n<p><\/p>\n<p>Het blijkt dat zelfs als we een tekenlijst vanaf nul opbouwen, we geen universele volgorde voor de tekens kunnen vaststellen. In verschillende nationale alfabetten die dezelfde letters gebruiken, kan de volgorde van deze letters verschillen. Bijvoorbeeld, in het Frans <em>\u00c6<\/em> wordt als een ligatuur beschouwd en gesorteerd als een string <em>AE<\/em>. In het Noors <em>\u00c6<\/em> wordt het een afzonderlijke letter, die na <em>Z<\/em>komt. Trouwens, naast ligaturen zoals <em>\u00c6<\/em> zijn er letters die door meerdere symbolen worden geschreven. In het Tsjechische alfabet is er de letter <em>Ch<\/em>, die tussen <em>H<\/em> en <em>I<\/em>.<\/p>\n<p><\/p>\n<p>staat. Behalve de verschillen in de alfabetten zijn er ook andere nationale tradities die invloed hebben op de sortering. Er rijst bijvoorbeeld de vraag: in welke volgorde moeten woorden die uit hoofdletters en kleine letters bestaan in het woordenboek worden geplaatst? Ook de specifieke manier waarop interpunctie wordt gebruikt, kan invloed hebben op de sortering. In het Spaans wordt aan het begin van een vraagzin een omgekeerd vraagteken geplaatst (<em>\u00bfTe gusta la m\u00fasica?<\/em>). In dit geval is het duidelijk dat vraagzinnen niet in een aparte cluster buiten het alfabet moeten worden gegroepeerd, maar hoe moet je strings met andere interpunctie sorteren?<\/p>\n<p><\/p>\n<p>Ik zal niet ingaan op de sortering van strings in talen die sterk verschillen van de Europese. Ik merk op dat in talen met een schrijfrichting van rechts naar links of van boven naar beneden, de symbolen in de strings waarschijnlijk in de leesvolgorde worden opgeslagen, en zelfs in niet-alfabetische schriftsoorten zijn er manieren om strings teken voor teken te ordenen. Bijvoorbeeld, hi\u00ebrogliefen kunnen worden geordend op basis van hun vorm (<noindex><a rel=\"nofollow\" href=\"https:\/\/studychinese.ru\/kljuchi\/\">de sleutels van Chinese hi\u00ebrogliefen<\/a><\/noindex>) of op basis van uitspraak. Hoe emoji's moeten worden geordend, heb ik eerlijk gezegd geen idee van, maar ook daarvoor kan wel iets worden bedacht.<\/p>\n<p><\/p>\n<p>Op basis van de bovengenoemde kenmerken zijn de belangrijkste vereisten voor het vergelijken van strings, gebaseerd op Unicode-tabellen, geformuleerd:<\/p>\n<p><\/p>\n<ul>\n<li>de vergelijking van strings is niet afhankelijk van de positie van de symbolen in de codeertabel;<\/li>\n<li>de reeksen van symbolen die een enkel teken vormen, worden in canonieke vorm gebracht (<em>A<\/em> + de bovenste cirkel is hetzelfde als <em>\u00c5<\/em>);<\/li>\n<li>); bij het vergelijken van strings wordt het teken in de context van de string beschouwd en, indien nodig, samengevoegd met buren tot een enkele vergelijkingseenheid (<em>Ch<\/em> in het Tsjechisch) of wordt het in meerdere (<em>\u00c6<\/em> in het Frans) opgesplitst.<\/li>\n<li>alle nationale kenmerken (alfabet, hoofdletters \/ kleine letters, interpunctie, volgorde van schrijfwijzen) moeten volledig handmatig ingesteld kunnen worden (emoji);<\/li>\n<li>vergelijking is niet alleen belangrijk voor sortering, maar ook op veel andere plaatsen, bijvoorbeeld bij het instellen van reeksen (substitutie {A\u2026 j} in <em>bash<\/em>);<\/li>\n<li>de vergelijking moet snel genoeg worden uitgevoerd.<\/li>\n<\/ul>\n<p><\/p>\n<p>Bovendien hebben de auteurs van het rapport eigenschappen van vergelijking geformuleerd waarop ontwikkelaars van het algoritme niet moeten vertrouwen:<\/p>\n<p><\/p>\n<ul>\n<li>het vergelijkingsalgoritme mag niet een aparte set symbolen vereisen voor elke taal (de Russische en Oekra\u00efense talen gebruiken gezamenlijk het grootste deel van het Cyrillische alfabet);<\/li>\n<li>de vergelijking mag niet steunen op de volgorde van symbolen in Unicode-tabellen;<\/li>\n<li>het gewicht van de string mag geen attribuut van de string zijn, aangezien dezelfde string in verschillende culturele contexten verschillende gewichten kan hebben;<\/li>\n<li>gewichten van strings kunnen veranderen bij het samenvoegen of splitsen (uit <em>x<\/em> &lt; <em>y<\/em> het is niet zo dat <em>xz<\/em> &lt; <em>yz<\/em>);<\/li>\n<li>verschillende strings met gelijke gewichten worden als gelijk beschouwd vanuit het perspectief van het sorteeralgoritme. Het introduceren van extra volgorde voor dergelijke strings is mogelijk, maar kan de prestaties verslechteren;<\/li>\n<li>bij herhaalde sorteringen kunnen strings met gelijke gewichten van plaats wisselen. Stabiliteit is een eigenschap van een specifiek sorteeralgoritme, en geen eigenschap van het string vergelijkingsalgoritme (zie punt hiervoor);<\/li>\n<li>sorteerregels kunnen in de loop van de tijd veranderen naarmate culturele tradities worden verfijnd \/ gewijzigd.<\/li>\n<\/ul>\n<p><\/p>\n<p>Het is ook opgemerkt dat het vergelijkingsalgoritme niets weet van de semantiek van de verwerkte strings. Strings die alleen uit cijfers bestaan, mogen niet als getallen worden vergeleken, en in lijsten met Engelse namen mag het lidwoord niet worden verwijderd (<em>Beatles, The<\/em>).<\/p>\n<p><\/p>\n<p>Om aan alle genoemde vereisten te voldoen, is een hi\u00ebrarchisch (eigenlijk vier niveaus) tabelalgoritme voor sorteren voorgesteld.<\/p>\n<p><\/p>\n<p>Eerst worden de symbolen in de string naar hun canonieke vorm gebracht en gegroepeerd in vergelijkingseenheden. Aan elke vergelijkingseenheid worden verschillende gewichten toegewezen die overeenkomen met verschillende vergelijkingsniveaus. De gewichten van de vergelijkingseenheden zijn elementen van geordende verzamelingen (in dit geval gehele getallen) die met elkaar vergeleken kunnen worden op groter-kleiner. Een speciale waarde <em>IGNORED<\/em> (0x0) betekent dat de betreffende eenheid op het overeenkomstige vergelijkingsniveau niet deelneemt aan de vergelijking. De vergelijking van strings kan meerdere keren worden herhaald, met gebruik van de gewichten van de betreffende niveaus. Op elk van de niveaus worden de gewichten van de vergelijkingseenheden van twee strings achtereenvolgens met elkaar vergeleken.<\/p>\n<p><\/p>\n<p>In verschillende implementaties van het algoritme voor verschillende nationale tradities kunnen de waarden van de co\u00ebffici\u00ebnten verschillen, maar de basisgewichtentabel maakt deel uit van de Unicode-standaard \u2014 <em>&quot;Default Unicode Collation Element Table&quot;<\/em> (<em>DUCET<\/em>). Ik wil opmerken dat het instellen van een variabele <em>LC_COLLATE<\/em> feitelijk een aanwijzing is voor de keuze van de gewichtentabel in de functie voor stringvergelijking.<\/p>\n<p><\/p>\n<p>Gewichtco\u00ebffici\u00ebnten <em>DUCET<\/em> zijn als volgt opgebouwd:<\/p>\n<p><\/p>\n<ul>\n<li>op het eerste niveau worden alle letters naar \u00e9\u00e9n hoofdlettertype omgezet, diakritische tekens worden weggelaten, en (niet alle) leestekens worden genegeerd;<\/li>\n<li>op het tweede niveau worden alleen diakritische tekens in aanmerking genomen;<\/li>\n<li>op het derde niveau wordt alleen de hoofdletter gebruikt;<\/li>\n<li>op het vierde niveau worden alleen leestekens in aanmerking genomen.<\/li>\n<\/ul>\n<p><\/p>\n<p>De vergelijking vindt plaats in meerdere rondes: eerst worden de co\u00ebffici\u00ebnten van het eerste niveau met elkaar vergeleken; als de gewichten overeenkomen, vindt een hervergelijking plaats met de gewichten van het tweede niveau; vervolgens, mogelijk, het derde en vierde.<\/p>\n<p><\/p>\n<p>De vergelijking eindigt wanneer er overeenkomstige vergelijkingseenheden met verschillende gewichten in de strings worden gevonden. Strings die op alle vier niveaus gelijke gewichten hebben, worden als gelijk aan elkaar beschouwd.<\/p>\n<p><\/p>\n<p>Dit algoritme (met een hoop extra technische details) gaf de naam aan rapport nr. 10 \u2014 <em>&quot;Unicode Collation Algorithm&quot;<\/em> (<em>UCA<\/em>).<\/p>\n<p><\/p>\n<p>Op dit punt wordt het sorteergedrag van ons voorbeeld iets duidelijker. Het zou goed zijn om dit te vergelijken met de Unicode-standaard.<\/p>\n<p><\/p>\n<p>Voor het testen van implementaties <em>UCA<\/em> is er een speciale <noindex><a rel=\"nofollow\" href=\"https:\/\/www.unicode.org\/Public\/UCA\/latest\/CollationTest.html\">test<\/a><\/noindex>, die gebruik maakt van <noindex><a rel=\"nofollow\" href=\"http:\/\/www.unicode.org\/Public\/UCA\/latest\/allkeys.txt\">gewichtbestand<\/a><\/noindex>, die <em>DUCET<\/em>. In het gewichtbestand zijn verschillende curiositeiten te vinden. Bijvoorbeeld, daar is de volgorde van dominosteentjes en Europese domino, evenals de volgorde van kleuren in een spel kaarten (symbool <em>1F000<\/em> en verder). De kleuren van de kaarten zijn gerangschikt volgens de brugregels \u2014 PCHK, en de kaarten binnen een kleur zijn in de volgorde T,2,3\u2026 K.<\/p>\n<p><\/p>\n<p>Handmatig controleren van de juistheid van het sorteren van strings volgens <em>DUCET<\/em> zou behoorlijk vermoeiend zijn, maar gelukkig voor ons bestaat er een voorbeeldige implementatie bibliotheek voor Unicode \u2014 &quot;<noindex><a rel=\"nofollow\" href=\"http:\/\/site.icu-project.org\/\">Internationale componenten voor Unicode<\/a><\/noindex>&quot; (<em>ICU<\/em>).<\/p>\n<p><\/p>\n<p>Op de website van deze bibliotheek, ontwikkeld in <em>IBM<\/em>, zijn demonstratiepagina's te vinden, waaronder <noindex><a rel=\"nofollow\" href=\"http:\/\/demo.icu-project.org\/icu-bin\/collation.html\">de pagina met het algoritme voor stringvergelijking<\/a><\/noindex>. We voeren onze teststrings in met de standaardinstellingen en, oh wonder, we krijgen perfecte Russische sortering.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Abakanov Mikhail;schilder\nYolkina Ella;kraanmachinist\nIvanov Andrei;loodgieter\nIvanova Alla;advocaat<\/code><\/pre>\n<p><\/p>\n<p>Trouwens, op de website <em>ICU<\/em> is er een verduidelijking over de werking van het algoritme voor vergelijking bij het verwerken van interpunctie. In de voorbeelden <noindex><a rel=\"nofollow\" href=\"http:\/\/userguide.icu-project.org\/collation\/faq\">Collation FAQ<\/a><\/noindex> worden het apostrof en het koppelteken genegeerd.<\/p>\n<p><\/p>\n<p>Unicode heeft ons geholpen, maar we moeten de oorzaken van het vreemde gedrag <em>sort<\/em> in <em>Linux<\/em> ergens anders zoeken.<\/p>\n<p><\/p>\n<h1 id=\"sortirovka-v-glibc\">Sorteren in glibc<\/h1>\n<p><\/p>\n<p>Een snelle blik op de broncode van de tool <em>sort<\/em> uit <em>GNU Core Utils<\/em> toonde aan dat de lokalisatie in de tool zelf neerkomt op het afdrukken van de huidige waarde van de variabele <em>LC_COLLATE<\/em> wanneer deze in de debug modus wordt uitgevoerd:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$ sort --debug buhg.txt &gt; buhg.srt\nsort: gebruikmakend van \u2018en_US.UTF8\u2019 sorteervoordelen<\/code><\/pre>\n<p><\/p>\n<p>Stringvergelijking gebeurt met de standaardfunctie <em>strcoll<\/em>, wat betekent dat alles interessante zich bevindt in de bibliotheek <em>glibc<\/em>.<\/p>\n<p><\/p>\n<p>Op <em>wiki<\/em> van het project <em>glibc<\/em> waaraan stringvergelijking is gewijd <noindex><a rel=\"nofollow\" href=\"https:\/\/sourceware.org\/glibc\/wiki\/Locales#LC_COLLATE\">\u00e9\u00e9n alinea<\/a><\/noindex>. Uit deze alinea kun je begrijpen dat <em>glibc<\/em> de sortering is gebaseerd op het voor ons bekende algoritme <em>UCA<\/em> (<em>Het Unicode sorteeralgoritme<\/em>) en\/of op een vergelijkbare standaard <em>ISO 14651<\/em> (<em>Internationale stringordening en vergelijking<\/em>). Voor de laatste standaard moet worden opgemerkt dat deze op de website <noindex><a rel=\"nofollow\" href=\"https:\/\/standards.iso.org\/ittf\/PubliclyAvailableStandards\">standards.iso.org<\/a><\/noindex> <em>ISO 14651<\/em> officieel als openbaar is verklaard, maar de betreffende link leidt naar een niet-bestaande pagina. Google geeft verschillende pagina's weer met links naar offici\u00eble websites die aanbieden een elektronische kopie van de standaard voor een paar honderd euro te kopen, maar op de derde of vierde pagina van de zoekresultaten vind je ook directe links naar <em>PDF<\/em>. Over het geheel genomen verschilt de standaard vrijwel niet van <em>UCA<\/em>, maar leest saaier, omdat het geen opvallende voorbeelden van nationale sorteerkenmerken bevat. <\/p>\n<p><\/p>\n<p>De meest interessante informatie op <em>wiki<\/em> bleek een link te zijn naar <noindex><a rel=\"nofollow\" href=\"https:\/\/sourceware.org\/bugzilla\/show_bug.cgi?id=14095\">bug tracker<\/a><\/noindex> met een discussie over de implementatie van stringvergelijking in <em>glibc<\/em>. Uit de discussie kun je leren dat in <em>glibc<\/em> voor stringvergelijking wordt gebruikt <em>ISO<\/em>een tabel <noindex><a rel=\"nofollow\" href=\"http:\/\/www.iso.org\/ittf\/ISO14651_2006_TABLE1_en.txt\">De Common Template Table<\/a><\/noindex> (<em>CTT<\/em>), waarvan het adres te vinden is in de bijlage <em>A<\/em> van de standaard <em>ISO 14651<\/em>. Tussen 2000 en 2015 is deze tabel in <em>glibc<\/em> had no maintainer and differed significantly (at least visually) from the current version of the standard. From 2015 to 2018, there was an adaptation to the new version of the table, and at the moment you may encounter either the new table variant (<em>CentOS 8<\/em>), or the old one (<em>CentOS 7<\/em>). <\/p>\n<p><\/p>\n<p>Now that we have all the information about the algorithm and auxiliary tables, we can return to the original problem and understand how to correctly sort rows in the Russian locale.<\/p>\n<p><\/p>\n<h1 id=\"iso-1465114652\">ISO 14651\/14652<\/h1>\n<p><\/p>\n<p>The source code of the table of interest to us <em>CTT<\/em> is located in the most distributions <em>Linux<\/em> in the directory <em>\/usr\/share\/i18n\/locales\/<\/em>. The table itself is in the file <em>iso14651_t1_common<\/em>. Then this file is included in the file with the directive <em>copy iso14651_t1_common<\/em> in the file <em>iso14651_t1<\/em>, which, in turn, is included in the national files, including <em>en_US<\/em> en <em>ru_RU<\/em>. In most distributions <em>Linux<\/em> all source files are included in the base installation, but if they are not present, you will have to install an additional package from the distribution.<\/p>\n<p><\/p>\n<p>dev.yaml <em>iso14651_t1<\/em> may seem terribly verbose, with non-obvious naming rules, but if you get into it, everything is quite simple. The structure is described in the standard <em>ISO 14652<\/em>, a copy of which can be downloaded from the site <noindex><a rel=\"nofollow\" href=\"http:\/\/www.open-std.org\/JTC1\/SC22\/WG20\/docs\/n972-14652ft.pdf\">open-std.org<\/a><\/noindex>. Another description of the file format can be read in <noindex><a rel=\"nofollow\" href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/9699919799\/basedefs\/V1_chap07.html\">de specificaties<\/a><\/noindex> <em>POSIX<\/em> van <em>OpenGroup<\/em>. As an alternative to reading the standard, you can study the source texts of the function <em>collate_read<\/em> in <em>glibc\/locale\/programs\/ld-collate.c<\/em>.<\/p>\n<p><\/p>\n<p>The structure of the file looks as follows:<\/p>\n<p><\/p>\n<p>By default, the character is used as an escape character, and the end of the line after the # symbol is a comment. Both characters can be overridden, which is done in the new version of the table:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">escape_char \/\ncomment_char %<\/code><\/pre>\n<p><\/p>\n<p>The file will contain tokens in the format <em>&lt;Uxxxx&gt;<\/em> of <em>&lt;Uxxxxxxxx&gt;<\/em> (waar <em>x<\/em> \u2014 a hexadecimal digit). This is the hexadecimal representation of Unicode code points in the encoding <em>UCS-4<\/em> (<em>UTF-32<\/em>). All other elements in angle brackets (including <em>&lt;Uxxxx_xxxx&gt;<\/em>, <em>&lt;2&gt;<\/em> and similar ones) are considered simple string constants without special meaning outside of context.<\/p>\n<p><\/p>\n<p>String <em>LC_COLLATE<\/em> tells us that the data describing string comparison begins next.<\/p>\n<p><\/p>\n<p>First, names for the weights in the comparison table and names for combinations of characters are set. Generally speaking, the two types of names belong to two different entities, but in the real file, they are mixed. The names of the weights are defined by the keyword <em>collating-symbol<\/em> (vergelijkingssymbool), aangezien Unicode-tekens met dezelfde gewichten als equivalente tekens worden beschouwd bij de vergelijking.<\/p>\n<p><\/p>\n<p>De totale lengte van de sectie in de huidige revisie van het bestand is ongeveer 900 regels. Ik heb voorbeelden uit verschillende plaatsen gehaald om de willekeurigheid van de namen en enkele soorten syntaxis te laten zien.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">LC_COLLATE\n\ncollating-symbol &lt;RES-1&gt;\ncollating-symbol &lt;BLK&gt;\ncollating-symbol &lt;MIN&gt;\ncollating-symbol &lt;WIDE&gt;\n...\ncollating-symbol &lt;ARABIC&gt;\ncollating-symbol &lt;ETHPC&gt;\ncollating-symbol &lt;OSMANYA&gt;\n...\ncollating-symbol &lt;S1D000&gt;..&lt;S1D35F&gt;\ncollating-symbol &lt;SFFFF&gt; % Gewaarborgde grootste symbolenwaarde. Houd aan het einde van deze lijst\n...\ncollating-element &lt;U0413_0301&gt; van &quot;&lt;U0413&gt;&lt;U0301&gt;&quot;\ncollating-element &lt;U0413_0341&gt; van &quot;&lt;U0413&gt;&lt;U0341&gt;&quot;<\/code><\/pre>\n<p><\/p>\n<ul>\n<li><em>collating-symbol<\/em> registreert een string <em>OSMANYA<\/em> in de naamgewichtentabel <\/li>\n<li><em>collating-symbol ..<\/em> registreert een reeks namen bestaande uit een prefix <em>S<\/em> en een hexadecimale numerieke suffix van <em>1D000<\/em> tot <em>1D35F<\/em>.<\/li>\n<li><em>FFFF<\/em> in <em>collating-symbol<\/em> verschijnt als een grote niet-negatieve integer in hexadecimale systeem, maar <em>&lt;SFFFF&gt;<\/em> het is gewoon een naam die eruit zou kunnen zien als <em>&lt;VERYBIGVAL&gt;<\/em> <\/li>\n<li>naam <em>&lt;U0413&gt;<\/em> betekent een codepunt in de codering <em>UCS-4<\/em><\/li>\n<li><em>collating-element &lt;U0413_0301&gt; van &quot;&lt;U0413&gt;&lt;U0301&gt;&quot;<\/em> registreert een nieuwe naam voor het paar Unicode-punten. <\/li>\n<\/ul>\n<p><\/p>\n<p>Wanneer de namen van de gewichten zijn gedefinieerd, worden de gewichten zelf ingesteld. Aangezien alleen de groter-kleiner relaties bij vergelijking van belang zijn, worden de gewichten bepaald door een eenvoudige volgorde van opsommen van de namen. Eerst worden de &quot;lichtere&quot; gewichten opgesomd, gevolgd door de &quot;zwaardere&quot;. Ik herinner eraan dat elk Unicode-teken vier verschillende gewichten krijgt toegewezen. Hier zijn ze samengevoegd in \u00e9\u00e9n geordende volgorde. Theoretisch kan elke symbolische naam op elk van de vier niveaus worden gebruikt, maar de opmerkingen geven aan dat de ontwikkelaars de namen mentaal op niveaus splitsen.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">% Symbolische gewichtstoewijzingen\n\n% Derde-niveau gewichtstoewijzingen\n\n\n\n\n...\n% Tweede-niveau gewichtstoewijzingen\n\n % COMBINING LOW LINE\n % COMBINING COMMA ABOVE\n % COMBINING REVERSED COMMA ABOVE\n...\n% Eerste-niveau gewichtstoewijzingen\n % HORIZONTALE TABULATIE\n % REGELAFBREKING\n % VERTICALE TABULATIE\n...\n % CYRILLIC KLEINE LETTER DE\n % CYRILLIC KLEINE LETTER KOMI DE\n % CYRILLIC KLEINE LETTER DJE\n % CYRILLIC KLEINE LETTER KOMI DJE\n % CYRILLIC KLEINE LETTER GJE\n % CYRILLIC KLEINE LETTER ZE MET DESCENDER\n % CYRILLIC KLEINE LETTER IE\n % CYRILLIC KLEINE LETTER IE MET BREVE\n % CYRILLIC KLEINE LETTER UKRAINI\u00cb IE\n % CYRILLIC KLEINE LETTER ZHE<\/code><\/pre>\n<p><\/p>\n<p>Ten slotte, de eigenlijke gewichten tabel.<\/p>\n<p><\/p>\n<p>De sectie gewichten is verpakt in rijen met sleutelwoorden <em>order_start<\/em> en <em>order_end<\/em>. Aanvullende parameters <em>order_start<\/em> bepalen in welke richting de rijen worden bekeken op elk vergelijkingsniveau. Standaard wordt de parameter gebruikt <em>forward<\/em>. Het lichaam van de sectie bestaat uit rijen die de tekencode en vier bijbehorende gewichten bevatten. De tekencode kan worden weergegeven door het teken zelf, een codepunt of een symbolische naam die eerder is gedefinieerd. Gewichten kunnen ook worden opgegeven door symbolische namen, codepunten of de tekens zelf. Als codepunten of tekens worden gebruikt, komt hun gewicht overeen met de numerieke waarde van het codepunt (de positie in de Unicode-tabel). Tekens die niet expliciet zijn opgegeven (zoals ik begrijp) worden beschouwd als toegevoegd aan de tabel met een primaire gewicht dat overeenkomt met de positie in de Unicode-tabel. Een speciale gewichtwaarde <em>IGNORE<\/em> betekent dat dit teken op het betreffende vergelijkingsniveau wordt genegeerd.<\/p>\n<p><\/p>\n<p>Om de structuur van de gewichten te demonstreren, heb ik drie vrij duidelijke fragmenten gekozen:<\/p>\n<p><\/p>\n<ul>\n<li>tekens die volledig worden genegeerd<\/li>\n<li>tekens die gelijk zijn aan het cijfer drie op de eerste twee niveaus<\/li>\n<li>begin van het Cyrillische alfabet, dat geen diakritische tekens bevat en daarom voornamelijk op de eerste en derde niveaus wordt gesorteerd.<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"plaintext\">order_start forward;forward;forward;forward,positie\n IGNORE;IGNORE;IGNORE;IGNORE % NULL (in 6429)\n IGNORE;IGNORE;IGNORE;IGNORE % START OF HEADING (in 6429)\n IGNORE;IGNORE;IGNORE;IGNORE % START OF TEXT (in 6429)\n...\n ;;; % DIGIT THREE\n ;;; % FULLWIDTH DIGIT THREE\n ;;; % PARENTHESIZED DIGIT THREE\n ;;; % DIGIT THREE FULL STOP\n ;;<FONT>; % MATHEMATICAL BOLD DIGIT THREE\n...\n ;;; % CYRILLIC SMALL LETTER A\n ;;; % CYRILLIC CAPITAL LETTER A\n ;;; % CYRILLIC SMALL LETTER A WITH BREVE\n ;;; % CYRILLIC SMALL LETTER A WITH BREVE\n...\n ;;; % CYRILLIC SMALL LETTER BE\n ;;; % CYRILLIC CAPITAL LETTER BE\n ;;; % CYRILLIC SMALL LETTER VE\n ;;; % CYRILLIC CAPITAL LETTER VE\n...\norder_end<\/code><\/pre>\n<p><\/p>\n<p>Nu kunnen we weer terugkeren naar de sortering van de voorbeelden aan het begin van het artikel. De val zit in dit gedeelte van de gewichten tabel:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">NEGEREN; NEGEREN; NEGEREN; % RUIMTE\n NEGEREN; NEGEREN; NEGEREN; % UITROEPTEKEN\n NEGEREN; NEGEREN; NEGEREN; % AANHAALTEKEN\n...<\/code><\/pre>\n<p><\/p>\n<p>Het is duidelijk dat in deze tabel leestekens uit de tabel zijn. <em>ASCII<\/em> (inclusief spaties) worden bij het vergelijken van strings vrijwel altijd genegeerd. Uitzonderingen zijn enkel de strings die in alles overeenkomen, behalve in leestekens die zich op overeenkomende posities bevinden. De strings uit mijn voorbeeld (na sortering) zien eruit als volgt voor het vergelijkingsalgoritme:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">AbakanovMikhailSchilders\nYolkinaEllakranovschitsa\nIvanovaAllaSchilders\nIvanovAndreiKlusjesman<\/code><\/pre>\n<p><\/p>\n<p>Gegeven dat in de weegset hoofdletters in het Russisch na kleine letters komen (op de derde niveau) <em>&lt;CAP&gt;<\/em> zwaarder dan <em>&lt;MIN&gt;<\/em>), is de sortering volkomen juist.<\/p>\n<p><\/p>\n<p>Bij het instellen van de variabele <em>LC_COLLATE=C<\/em> wordt een speciale tabel geladen die byte-voor-byte vergelijking bepaalt.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">static const uint32_t collseqwc[] =\n{\n  8, 1, 8, 0x0, 0xff,\n  \/* 1e-niveau tabel *\/\n  6 * sizeof (uint32_t),\n  \/* 2e-niveau tabel *\/\n  7 * sizeof (uint32_t),\n  \/* 3e-niveau tabel *\/\n  L'x00', L'x01', L'x02', L'x03', L'x04', L'x05', L'x06', L'x07',\n  L'x08', L'x09', L'x0a', L'x0b', L'x0c', L'x0d', L'x0e', L'x0f',\n\n...\n  L'xf8', L'xf9', L'xfa', L'xfb', L'xfc', L'xfd', L'xfe', L'xff'\n};<\/code><\/pre>\n<p><\/p>\n<p>Aangezien de Unicode-codepunt \u0401 voor A staat, worden de strings ook zo gesorteerd.<\/p>\n<p><\/p>\n<h1 id=\"tekstovye-i-dvoichnye-tablicy\">Tekst- en binaire tabellen<\/h1>\n<p><\/p>\n<p>Het is duidelijk dat het vergelijken van strings een zeer vaak voorkomende operatie is, terwijl het parseren van de tabel <em>CTT<\/em> een vrij kostbare procedure is. Voor het optimaliseren van de toegang tot de tabel wordt deze gecompileerd naar een binaire vorm met het commando <em>localedef<\/em>.<\/p>\n<p><\/p>\n<p>Opdracht <em>localedef<\/em> neemt als parameters een bestand met de nationale kenmerkentabel (optie <em>-i<\/em>), waarin alle symbolen worden voorgesteld door Unicode-codepunten, en een overeenstemmingsbestand voor Unicode-codepunten met een specifieke codering (optie <em>-f<\/em>). Als resultaat van de bewerking worden er binaire bestanden voor de locale aangemaakt met de naam die in de laatste parameter is opgegeven.<\/p>\n<p><\/p>\n<p><em>Glibc<\/em> ondersteunt twee formaten van binaire bestanden: &quot;traditioneel&quot; en &quot;modern&quot;.<\/p>\n<p><\/p>\n<p>Het traditionele formaat houdt in dat de naam van de locale een naam is van de subdirectory in <em>\/usr\/lib\/locale\/<\/em>. In deze subdirectory worden binaire bestanden opgeslagen <em>LC_COLLATE<\/em>, <em>LC_CTYPE<\/em>, <em>LC_TIME<\/em> enzovoort. Het bestand <em>LC_IDENTIFICATION<\/em> bevat de formele naam van de locale (die kan verschillen van de naam van de directory) en opmerkingen.<\/p>\n<p><\/p>\n<p>Het moderne formaat veronderstelt dat alle locales in een enkele archief zijn opgeslagen <em>\/usr\/lib\/locale\/locale-archive<\/em>, die wordt weergegeven in het virtuele geheugen van alle processen die het gebruiken. <em>glibc<\/em>De naam van de locale in het moderne formaat ondergaat enige canonisatie \u2014 in de naamgeving van encoderingen blijven alleen cijfers en letters behouden, omgezet naar kleine letters. Dus <em>nl_NL.KOI8-R<\/em>, zal worden bewaard als <em>nl_NL.koi8r<\/em>.<\/p>\n<p><\/p>\n<p>Ingangsbestanden worden gezocht in de huidige map, evenals in de mappen <em>\/usr\/share\/i18n\/locales\/<\/em> en <em>\/usr\/share\/i18n\/charmaps\/<\/em> voor bestanden <em>CTT<\/em> en bestanden van encoderingen respectievelijk.<\/p>\n<p><\/p>\n<p>Bijvoorbeeld, het commando<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">localedef -i nl_NL -f MAC-CYRILLIC nl_NL.MAC-CYRILLIC<\/code><\/pre>\n<p><\/p>\n<p>compileert het bestand <em>\/usr\/share\/i18n\/locales\/ru_RU<\/em> met behulp van het encoderingbestand <em>\/usr\/share\/i18n\/charmaps\/MAC-CYRILLIC.gz<\/em> en zal het resultaat opslaan in <em>\/usr\/lib\/locale\/locale-archive<\/em> under the name <em>nl_NL.maccyrillic<\/em><\/p>\n<p><\/p>\n<p>Als je de variabele <em>LANG=en_US.UTF-8<\/em> instelt, <em>glibc<\/em> zal het binaire bestanden van de locale zoeken in de volgende volgorde van bestanden en mappen:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">\/usr\/lib\/locale\/locale-archive\n\/usr\/lib\/locale\/en_US.UTF-8\/\n\/usr\/lib\/locale\/en_US\/\n\/usr\/lib\/locale\/enUTF-8\/\n\/usr\/lib\/locale\/en\/<\/code><\/pre>\n<p><\/p>\n<p>Als de locale in zowel traditionele als moderne formaten voorkomt, heeft de moderne de voorkeur.<\/p>\n<p><\/p>\n<p>Je kunt de lijst met gecompileerde locales bekijken met het commando <em>locale -a<\/em>.<\/p>\n<p><\/p>\n<h1 id=\"podgotovka-svoey-tablicy-sravneniya\">Het voorbereiden van je eigen vergelijkingsmatrix<\/h1>\n<p><\/p>\n<p>Nu, gewapend met kennis, kun je je eigen ideale vergelijkingsmatrix voor stringvergelijkingen cre\u00ebren. Deze matrix moet correct Russische letters vergelijken, inclusief de letter \u0401, en rekening houden met leestekens volgens de tabel. <em>ASCII<\/em>.<\/p>\n<p><\/p>\n<p>Het proces van het voorbereiden van je eigen sorteertabel bestaat uit twee fasen: het bewerken van de gewichtentabel en het compileren ervan naar binaire vorm met het commando. <em>localedef<\/em>.<\/p>\n<p><\/p>\n<p>Om de vergelijkingsmatrix met minimale bewerkingskosten aan te passen, biedt het formaat <em>ISO 14652<\/em> secties voor het aanpassen van de gewichten van de bestaande tabel. Een sectie begint met het sleutelwoord <em>reorder-after<\/em> en de positionele aanwijzing, na welke de vervangingen plaatsvinden. De sectie eindigt met de regel <em>reorder-end<\/em>. Als het nodig is om meerdere delen van de tabel te corrigeren, wordt er een sectie voor elk deel gemaakt.<\/p>\n<p><\/p>\n<p>Ik heb nieuwe versies van de bestanden gekopieerd <em>iso14651_t1_common<\/em> en <em>ru_RU<\/em> uit de repository <em>glibc<\/em> naar mijn thuisdirectory ~\/.local\/share\/i18n\/locales\/ en iets aangepast in de sectie <em>LC_COLLATE<\/em> in <em>ru_RU<\/em>. Nieuwe versies van bestanden zijn volledig compatibel met mijn versie. <em>glibc<\/em>Als je de oude versies van de bestanden wilt gebruiken, moet je de symbolische namen en de plaats waar de vervangingen beginnen in de tabel wijzigen.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">LC_COLLATE\n% Kopieer de sjabloon van ISO\/IEC 14651\ncopy &quot;iso14651_t1&quot;\nreorder-after &lt;U000D&gt;\n&lt;U0020&gt; &lt;S0020&gt;;&lt;BASE&gt;;&lt;MIN&gt;&lt;U0020&gt; % RUIMTE\n&lt;U0021&gt; &lt;S0021&gt;;&lt;BASE&gt;&lt;MIN&gt;&lt;U0021&gt; % UITROEPTEKEN\n&lt;U0022&gt; &lt;S0022&gt;;&lt;BASE&gt;&lt;MIN&gt;&lt;U0022&gt; % AANHALINGSTEKEN\n...\n&lt;U007D&gt; &lt;S007D&gt;;&lt;BASE&gt;&lt;MIN&gt;&lt;U007D&gt; % RECHTSDE CURLY BRAKET\n&lt;U007E&gt; &lt;S007E&gt;;&lt;BASE&gt;&lt;MIN&gt;&lt;U007E&gt; % TILDE\nreorder-end\nEINDE LC_COLLATE<\/code><\/pre>\n<p><\/p>\n<p>Eigenlijk zou het nodig zijn om de velden te wijzigen in <em>LC_IDENTIFICATION<\/em> zodat ze naar de locatie verwijzen <em>ru_MY<\/em>, maar in mijn voorbeeld was dit niet nodig omdat ik de zoekopdracht naar locaties in het archief heb uitgesloten <em>locale-archive<\/em>.<\/p>\n<p><\/p>\n<p>Om <em>localedef<\/em> werkte met bestanden in mijn map via de variabele <em>I18NPATH<\/em> je kunt een extra map toevoegen voor het zoeken naar invoerbestanden, en de map voor het opslaan van binaire bestanden kan worden opgegeven als een pad met schuine strepen:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; I18NPATH=~\/.local\/share\/i18n localedef -i ru_RU -f UTF-8 ~\/.local\/lib\/locale\/ru_MY.UTF-8<\/code><\/pre>\n<p><\/p>\n<p><em>POSIX<\/em> dit gaat ervan uit dat in <em>LANG<\/em> je absolute paden naar mappen met locatiebestanden kunt schrijven, beginnend met een schuin streepje, maar <em>glibc<\/em> in <em>Linux<\/em> iedereen paden beschouwt vanaf de basisdirectory, die kan worden overschreven via de variabele <em>LOCPATH<\/em>. Na het instellen van <em>LOCPATH=~\/.local\/lib\/locale\/<\/em> zullen alle bestanden die met lokalisatie verband houden, alleen in mijn map worden gezocht. Het archief van locaties met de ingestelde variabele <em>LOCPATH<\/em> wordt genegeerd.<\/p>\n<p><\/p>\n<p>Hier is de beslissende test:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LANG=ru_MY.UTF-8 LOCPATH=~\/.local\/lib\/locale\/ sort buhg.txt\nAbakanov Michail;schilder\nJolkina Ella;kraanmachinist\nIvanov Andrej;loodgieter\nIvanova Alla;advocaat<\/code><\/pre>\n<p><\/p>\n<p>Hoera! We hebben het gedaan!<\/p>\n<p><\/p>\n<h1 id=\"rabota-nad-oshibkami\">Fouten herstellen<\/h1>\n<p><\/p>\n<p>Ik heb al geantwoord op de vragen over het sorteren van rijen die aan het begin zijn gesteld, maar er zijn nog een paar vragen over fouten \u2014 zichtbare en onzichtbare.<\/p>\n<p><\/p>\n<p>Laten we terugkeren naar de oorspronkelijke taak.<\/p>\n<p><\/p>\n<p>En het programma <em>sort<\/em> en het programma <em>join<\/em> maken gebruik van dezelfde functies voor het vergelijken van rijen uit <em>glibc<\/em>. Hoe is het mogelijk dat <em>join<\/em> een sorteerfout gaf op rijen gesorteerd door de opdracht <em>sort<\/em> in de locatie <em>en_US.UTF-8<\/em>? \u041e\u0442\u0432\u0435\u0442 \u043f\u0440\u043e\u0441\u0442: <em>sort<\/em> vergelijkt de volledige rij, terwijl <em>join<\/em> alleen de sleutel vergelijkt, die standaard het begin van de rij is tot het eerste spatiekarakter. In mijn voorbeeld leidde dit tot een foutmelding omdat de sortering van de eerste woorden in de rijen niet overeenkwam met de sortering van de volledige rijen.<\/p>\n<p><\/p>\n<p>De locatie <em>&quot;C&quot;<\/em> garandeert dat de gesorteerde rijen met de beginonderdelen tot de eerste spatie ook sorteren, maar dit verbergt alleen de fout. Je kunt zulke gegevens verzamelen (mensen met dezelfde achternamen, maar verschillende voornamen), die zonder foutmelding een onjuist resultaat bij het samenvoegen van bestanden zouden opleveren. Als we willen dat <em>join<\/em> de rijen van bestanden op naam en achternaam samenvoegt, dan is de juiste manier om dit te doen het expliciet opgeven van de veldscheidingsteken en sorteren op het sleutelveld, in plaats van op de hele rij. In dat geval zal ook de samenvoeging correct verlopen en zullen er in geen enkele locatie fouten optreden:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; sort -t ; -k 1 buhg.txt &gt; buhg.srt\n$&gt; sort -t ; -k 1 mail.txt &gt; mail.srt\n$&gt; join -t ; buhg.srt mail.srt &gt; result<\/code><\/pre>\n<p><\/p>\n<p>Een succesvol uitgevoerd voorbeeld in codering <em>CP1251<\/em> bevat nog een andere fout. Het probleem is dat in alle distributies die ik ken <em>Linux<\/em> de pakketten geen gecompileerde locale bevatten <em>ru_RU.CP1251<\/em>. Als de gecompileerde locale niet gevonden wordt, dan <em>sort<\/em> gebruikt het stilzwijgend byte-voor-byte vergelijking, wat we hebben waargenomen.<\/p>\n<p><\/p>\n<p>Trouwens, er is nog een klein probleem met het ontbreken van gecompileerde locales. De opdracht <em>LOCPATH=\/tmp locale -a<\/em> geeft een lijst van alle locales terug in <em>locale-archive<\/em>, maar met de ingestelde variabele <em>LOCPATH<\/em> voor alle programma's (inclusief het programma zelf <em>locale<\/em>) zijn deze locales niet beschikbaar.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LOCPATH=\/tmp locale -a | grep en_US\nlocale: Kan LC_CTYPE niet instellen op standaard locale: Bestand of map bestaat niet\nlocale: Kan LC_MESSAGES niet instellen op standaard locale: Bestand of map bestaat niet\nlocale: Kan LC_COLLATE niet instellen op standaard locale: Bestand of map bestaat niet\nen_US\nen_US.iso88591\nen_US.iso885915\nen_US.utf8\n\n$&gt; LC_COLLATE=en_US.UTF-8 sort --debug\nsort: gebruikmakend van \u2018en_US.UTF-8\u2019 sorteernormen\n\n$&gt; LOCPATH=\/tmp LC_COLLATE=en_US.UTF-8 sort --debug\nsort: gebruikmakend van eenvoudige byte vergelijking<\/code><\/pre>\n<p><\/p>\n<h1 id=\"zaklyuchenie\">Conclusie<\/h1>\n<p><\/p>\n<p>Als je een programmeur bent die gewend is te denken dat strings een reeks bytes zijn, is je keuze <em>LC_COLLATE=C<\/em>.<\/p>\n<p><\/p>\n<p>Als je een lingu\u00efst of woordenboekmaker bent, dan kun je beter je eigen locale compileren.<\/p>\n<p><\/p>\n<p>Als je een gewone gebruiker bent, dan hoef je alleen maar te wennen aan het feit dat de opdracht <em>ls -a<\/em> bestanden begint met een punt, samen met bestanden die beginnen met een letter, en <em>Midnight Commander<\/em>, die zijn interne functies voor het sorteren van namen gebruikt, plaatst bestanden die beginnen met een punt, aan het begin van de lijst.<\/p>\n<p><\/p>\n<h1 id=\"ssylki\">Links<\/h1>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/unicode.org\/reports\/tr10\/\">Rapport \u211610 Unicode collation algorithm <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/www.unicode.org\/Public\/UCA\/latest\/allkeys.txt\">Gewichten van symbolen op unicode.org <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/userguide.icu-project.org\/intro\"><em>ICU<\/em> \u2014 de implementatie van de bibliotheek voor werken met Unicode van IBM. <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/demo.icu-project.org\/icu-bin\/collation.html\">Sorteringstest met behulp van <em>ICU<\/em> <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/www.iso.org\/ittf\/ISO14651_2006_TABLE1_en.txt\">Gewichten van symbolen in <em>ISO 14651<\/em> <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/www.open-std.org\/JTC1\/SC22\/WG20\/docs\/n972-14652ft.pdf\">Beschrijving van het bestandsformaat met gewichten <em>ISO 14652<\/em> <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/sourceware.org\/bugzilla\/show_bug.cgi?id=14095\">Discussie over string vergelijking in <em>glibc<\/em><\/a><\/noindex><\/p>\n<p>Bron: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/503960\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0412\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u0430\u0434\u0440\u0435\u0441\u0430\u0445 e-mail \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u0447\u0442\u043e\u0432\u043e\u0439 \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438, \u0441 \u0434\u043e\u043b\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0438\u0437 \u0431\u0430\u0437\u044b \u043e\u0442\u0434\u0435\u043b\u0430 \u043a\u0430\u0434\u0440\u043e\u0432. \u041e\u0431\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0431\u044b\u043b\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0432 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0435 \u042e\u043d\u0438\u043a\u043e\u0434 UTF-8 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b \u0441 \u044e\u043d\u0438\u043a\u0441\u043e\u0432\u0441\u043a\u0438\u043c\u0438 \u043a\u043e\u043d\u0446\u0430\u043c\u0438 \u0441\u0442\u0440\u043e\u043a. \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 mail.txt \u0418\u0432\u0430\u043d\u043e\u0432 \u0410\u043d\u0434\u0440\u0435\u0439;ia@example.com \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 buhg.txt \u0418\u0432\u0430\u043d\u043e\u0432\u0430 \u0410\u043b\u043b\u0430;\u043c\u0430\u043b\u044f\u0440 \u0401\u043b\u043a\u0438\u043d\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-83055","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0412\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u0430\u0434\u0440\u0435\u0441\u0430\u0445 e-mail \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u0447\u0442\u043e\u0432\u043e\u0439 \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438, \u0441.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a Linux\u2019\u043e\u0432\u0441\u043a\u0438\u0439 sort \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0412\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u0430\u0434\u0440\u0435\u0441\u0430\u0445 e-mail \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u0447\u0442\u043e\u0432\u043e\u0439 \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438, \u0441.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-27T23:42:15+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-27T23:42:15+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Hoe Linux 'sort' strings sorteert | ProHoster","description":"Inleiding Het begon allemaal met een kort script dat informatie over e-mailadressen van medewerkers moest combineren, verkregen uit de mailinglijst.","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a Linux\u2019\u043e\u0432\u0441\u043a\u0438\u0439 sort \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 | ProHoster","og:description":"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0412\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u0430\u0434\u0440\u0435\u0441\u0430\u0445 e-mail \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u0447\u0442\u043e\u0432\u043e\u0439 \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438, \u0441.","og:url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-27T23:42:15+00:00","article:modified_time":"2020-05-27T23:42:15+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"83055","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 15:26:22","updated":"2022-09-27 19:16:08","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/83055","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=83055"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/83055\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=83055"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=83055"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=83055"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}