{"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\/it\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki","title":{"rendered":"Come sort Linux ordina le stringhe","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h1 id=\"vvedenie\">Introduzione<\/h1>\n<p><\/p>\n<p>Tutto \u00e8 iniziato con un breve script che doveva unire le informazioni sugli indirizzi <em>e-mail<\/em> dei dipendenti, ottenute da un elenco di utenti della mailing list, con le posizioni dei dipendenti, ottenute dal database del personale. Entrambi gli elenchi sono stati esportati in file di testo in codifica Unicode <em>UTF-8<\/em> e salvati con terminazioni di riga Unix.<\/p>\n<p><\/p>\n<p>Contenuto <em>mail.txt<\/em><\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Ivanov Andrei;ia@example.com<\/code><\/pre>\n<p><\/p>\n<p>Contenuto <em>buhg.txt<\/em><\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Ivanova Alla;imbianchino\nEltkina Ella;gruista\nIvanov Andrei;installatore\nAbakanov Michail;imbianchino<\/code><\/pre>\n<p><\/p>\n<p>Per unire i file, sono stati ordinati con il comando Unix <em>sort<\/em> e forniti come input a un programma Unix <em>upgrade<\/em>, che \u00e8 terminato inaspettatamente con un errore: <\/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: non \u00e8 ordinato: Ivanov Andrei;installatore<\/code><\/pre>\n<p><\/p>\n<p>Una revisione del risultato dell'ordinamento ha mostrato che, in generale, l'ordinamento era corretto, ma nel caso di nomi maschili e femminili coincidenti, i nomi femminili vengono prima:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; sort buhg.txt\nAbakanov Michail;imbianchino\nEltkina Ella;gruista\nIvanova Alla;imbianchino\nIvanov Andrei;installatore<\/code><\/pre>\n<p><\/p>\n<p>Sembra un bug nell'ordinamento Unicode o un'espressione del femminismo nell'algoritmo di ordinamento. La prima opzione \u00e8 certamente pi\u00f9 plausibile.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Lasciamo per ora <em>upgrade<\/em> e concentriamoci su <em>sort<\/em>. Proviamo a risolvere il problema con il metodo del tentativo ed errore. Per cominciare, cambiamo la localizzazione da <em>en_US<\/em> in <em>ru_RU<\/em>. Per l'ordinamento sarebbe bastato impostare la variabile d'ambiente <em>LC_COLLATE<\/em>, ma non ci accontenteremo:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LANG=ru_RU.UTF-8 sort buhg.txt\nAbakanov Michail;imbianchino\nEltkina Ella;gruista\nIvanova Alla;imbianchino\nIvanov Andrei;installatore<\/code><\/pre>\n<p><\/p>\n<p>Niente \u00e8 cambiato.<\/p>\n<p><\/p>\n<p>Proviamo a riconvertire i file in una codifica a byte singolo: <\/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>Ancora una volta, niente \u00e8 cambiato.<\/p>\n<p><\/p>\n<p>Non abbiamo scelta, dovremo cercare una soluzione su Internet. Non ci sono informazioni specifiche sulle famiglie russe, ma ci sono domande su altre stranezze nell'ordinamento. Ecco, per esempio, un problema: <noindex><a rel=\"nofollow\" href=\"https:\/\/serverfault.com\/questions\/95579\/unix-sort-treats-dash-characters-as-invisible\/95593\">unix sort tratta i caratteri &#8216;-&#8216; (trattino) come invisibili<\/a><\/noindex>. In breve, le stringhe &quot;a-b&quot;, &quot;aa&quot;, &quot;ac&quot; vengono ordinati come &quot;aa&quot;, &quot;a-b&quot;, &quot;ac&quot;.<\/p>\n<p><\/p>\n<p>La risposta \u00e8 sempre la stessa: usa la localizzazione per programmatori <em>&quot;C&quot;<\/em> e sarete felici. Proviamo:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LANG=C sort buhg.txt\nEltkina Ella;gruista\nAbakanov Michail;imbianchino\nIvanov Andrei;installatore\nIvanova Alla;avvocato<\/code><\/pre>\n<p><\/p>\n<p>Qualcosa \u00e8 cambiato. Gli Ivanov sono stati ordinati nel modo giusto, ma Eltkina \u00e8 scomparsa da qualche parte. Torniamo al compito originale:<\/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>Ha funzionato senza errori, come promesso da Internet. E questo nonostante ci sia \u0401\u043b\u043a\u0438\u043d\u0430 nella prima riga.<\/p>\n<p><\/p>\n<p>Il problema sembra risolto, ma per precauzione proviamo un'altra codifica russa: quella di Windows. <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>Il risultato dell'ordinamento, strano ma vero, corrisponder\u00e0 alla localizzazione. <em>&quot;C&quot;<\/em>, e l'intero esempio, di conseguenza, passa senza errori. \u00c8 una sorta di mistero.<\/p>\n<p><\/p>\n<p>Non amo i misteri nella programmazione, poich\u00e9 in genere mascherano errori. Dovr\u00f2 prendere seriamente in considerazione come funziona <em>sort<\/em> e su cosa influisce <em>LC_COLLATE<\/em> .<\/p>\n<p><\/p>\n<p>Alla fine cercher\u00f2 di rispondere alle domande:<\/p>\n<p><\/p>\n<ul>\n<li>perch\u00e9 i cognomi femminili non venivano ordinati correttamente<\/li>\n<li>perch\u00e9 <em>LANG=ru_RU.CP1251<\/em> si \u00e8 rivelata equivalente <em>LANG=C<\/em><\/li>\n<li>perch\u00e9 <em>sort<\/em> e <em>upgrade<\/em> hanno differenti rappresentazioni dell'ordine delle righe ordinate<\/li>\n<li>perch\u00e9 ci sono errori in tutti i miei esempi<\/li>\n<li>infine, come ordinare le righe secondo il proprio gusto<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"sortirovka-v-yunikode\">Ordinamento in Unicode<\/h1>\n<p><\/p>\n<p>La prima tappa sar\u00e0 il rapporto tecnico n. 10 intitolato <noindex><a rel=\"nofollow\" href=\"https:\/\/unicode.org\/reports\/tr10\/\">algoritmo di collazione Unicode<\/a><\/noindex> sul sito <noindex><a rel=\"nofollow\" href=\"https:\/\/unicode.org\">unicode.org<\/a><\/noindex>. Il rapporto contiene molti dettagli tecnici, quindi permettetemi di fornire una breve sintesi delle idee principali.<\/p>\n<p><\/p>\n<p><em>Collazione<\/em> \u2014 &quot;confronto&quot; di stringhe \u2014 \u00e8 alla base di qualsiasi algoritmo di ordinamento. Gli algoritmi stessi possono variare (&quot;bubble sort&quot;, &quot;merge sort&quot;, &quot;quick sort&quot;), ma tutti utilizzeranno il confronto di coppie di stringhe per determinare l'ordine di successione.<\/p>\n<p><\/p>\n<p>Ordinare le righe in un linguaggio naturale \u00e8 un problema piuttosto complesso. Anche nelle pi\u00f9 semplici codifiche a byte singolo, l'ordine delle lettere nell'alfabeto, in qualsivoglia modo diverso dall'alfabeto latino inglese, non corrisponder\u00e0 pi\u00f9 all'ordine dei valori numerici che codificano quelle lettere. Cos\u00ec, nell'alfabeto tedesco, la lettera <em>\u00d6<\/em> si trova tra <em>O<\/em> e <em>P<\/em>, ma nella codifica <em>CP850<\/em> si colloca tra <em>\u00ff<\/em> e <em>\u00dc<\/em>.<\/p>\n<p><\/p>\n<p>Si pu\u00f2 tentare di astrarsi dalla codifica specifica e considerare le &quot;lettere ideali&quot; disposte in un certo ordine, come avviene in Unicode. Le codifiche <em>UTF8<\/em>, <em>UTF16<\/em> o la codifica a byte singolo <em>KOI8-R<\/em> (se \u00e8 necessario un sottoinsieme limitato di Unicode) daranno rappresentazioni numeriche diverse delle lettere, ma faranno riferimento agli stessi elementi della tabella di base. <\/p>\n<p><\/p>\n<p>Scopriamo che anche costruendo una tabella dei caratteri da zero, non saremo in grado di impostare un ordine universale dei caratteri. Negli alfabeti nazionali diversi che utilizzano le stesse lettere, l'ordine di queste lettere pu\u00f2 variare. Ad esempio, nella lingua francese <em>\u00c6<\/em> sar\u00e0 considerata una ligatura e ordinata come una stringa <em>AE<\/em>. Nella lingua norvegese, invece, <em>\u00c6<\/em> sar\u00e0 una lettera separata, che si trova dopo <em>Z<\/em>. A proposito, oltre alle ligature come <em>\u00c6<\/em> esistono lettere scritte con pi\u00f9 caratteri. Ad esempio, nell'alfabeto ceco c'\u00e8 la lettera <em>Ch<\/em>, che si trova tra <em>H<\/em> e <em>I<\/em>.<\/p>\n<p><\/p>\n<p>Oltre alla differenza negli alfabeti, ci sono anche altre tradizioni nazionali che influenzano l'ordinamento. In particolare, si pone la questione: in quale ordine dovrebbero seguire in un dizionario le parole composte da lettere maiuscole e minuscole? Inoltre, l'uso della punteggiatura pu\u00f2 influenzare l'ordinamento. Nella lingua spagnola, all'inizio di una frase interrogativa si colloca un punto interrogativo rovesciato (<em>\u00bfTe gusta la m\u00fasica?<\/em>). In questo caso \u00e8 evidente che le frasi interrogative non dovrebbero essere raggruppate in un cluster separato al di fuori dell'alfabeto, ma come si devono ordinare le stringhe con altri segni di punteggiatura?<\/p>\n<p><\/p>\n<p>Non mi soffermer\u00f2 sull'ordinamento delle stringhe in lingue molto diverse da quelle europee. Sottolineo che nelle lingue con direzione di scrittura da destra a sinistra o dall'alto verso il basso, i caratteri nelle stringhe vengono probabilmente memorizzati nell'ordine di lettura, e anche nelle scritture non alfabetiche ci sono modi per ordinare le stringhe carattere per carattere. Ad esempio, i caratteri possono essere ordinati in base alla loro forma (<noindex><a rel=\"nofollow\" href=\"https:\/\/studychinese.ru\/kljuchi\/\">chiavi dei caratteri cinesi<\/a><\/noindex>) o sulla base della pronuncia. Come dovrebbero essere ordinati gli emoji, francamente, non lo so, ma anche per loro si pu\u00f2 inventare qualcosa.<\/p>\n<p><\/p>\n<p>Sulla base delle caratteristiche sopra elencate, sono stati formulati i requisiti fondamentali per il confronto delle stringhe, basati sulle tabelle Unicode:<\/p>\n<p><\/p>\n<ul>\n<li>Il confronto delle stringhe non dipende dalla posizione dei caratteri nella tabella dei codici;<\/li>\n<li>le sequenze di caratteri che formano un unico carattere vengono portate a una forma canonica (<em>A<\/em> + il cerchietto sopra \u00e8 lo stesso di <em>\u00c5<\/em>);<\/li>\n<li>nel confronto delle stringhe, il carattere viene considerato nel contesto della stringa e, se necessario, viene unito con i vicini in un'unit\u00e0 di confronto (<em>Ch<\/em> in ceco) oppure viene suddiviso in pi\u00f9 unit\u00e0 (<em>\u00c6<\/em> in francese);<\/li>\n<li>tutte le peculiarit\u00e0 nazionali (alfabeto, maiuscole\/minuscole, segni di punteggiatura, ordine dei tipi di scrittura) devono essere configurate fino all'assegnazione manuale dell'ordine (emoji);<\/li>\n<li>il confronto \u00e8 importante non solo per l'ordinamento, ma anche in molti altri contesti, ad esempio per definire gli intervalli di righe (sostituzione {A\u2026 z} in <em>bash<\/em>);<\/li>\n<li>il confronto deve essere eseguito piuttosto rapidamente.<\/li>\n<\/ul>\n<p><\/p>\n<p>Inoltre, gli autori del rapporto hanno definito delle propriet\u00e0 di confronto su cui i programmatori dell'algoritmo non devono basarsi:<\/p>\n<p><\/p>\n<ul>\n<li>l'algoritmo di confronto non deve richiedere un insieme separato di caratteri per ogni lingua (le lingue russa e ucraina condividono la maggior parte dei caratteri cirillici);<\/li>\n<li>il confronto non deve dipendere dall'ordine dei caratteri nelle tabelle Unicode;<\/li>\n<li>il peso di una stringa non deve essere un attributo della stringa, poich\u00e9 la stessa stringa in diversi contesti culturali pu\u00f2 avere pesi differenti;<\/li>\n<li>i pesi delle stringhe possono variare durante fusioni o divisioni (da <em>x<\/em> &lt; <em>y<\/em> non si deve intendere che <em>xz<\/em> &lt; <em>yz<\/em>);<\/li>\n<li>stringhe diverse che hanno lo stesso peso sono considerate uguali dal punto di vista dell'algoritmo di ordinamento. Introduzione di ulteriori ordinamenti di tali stringhe \u00e8 possibile, ma potrebbe ridurre le prestazioni;<\/li>\n<li>in ordinamenti ripetuti, le stringhe con lo stesso peso potrebbero scambiarsi di posto. La stabilit\u00e0 \u00e8 una propriet\u00e0 specifica di un algoritmo di ordinamento, e non una propriet\u00e0 dell'algoritmo di confronto delle stringhe (vedi punto precedente);<\/li>\n<li>le regole di ordinamento possono cambiare nel tempo con la definizione\/cambiamento delle tradizioni culturali.<\/li>\n<\/ul>\n<p><\/p>\n<p>\u00c8 inoltre specificato che l'algoritmo di confronto non ha conoscenze sulla semantica delle stringhe elaborate. Pertanto, le stringhe costituite solo da cifre non devono essere confrontate come numeri, e negli elenchi di nomi inglesi non deve essere rimosso l'articolo (<em>Beatles, The<\/em>).<\/p>\n<p><\/p>\n<p>Per soddisfare tutti i requisiti indicati \u00e8 stato proposto un algoritmo di ordinamento tabellare multistrato (in realt\u00e0 a quattro livelli).<\/p>\n<p><\/p>\n<p>Prima, i caratteri nella stringa sono portati alla forma canonica e raggruppati in unit\u00e0 di confronto. A ciascuna unit\u00e0 di confronto vengono assegnati vari pesi, corrispondenti a diversi livelli di confronto. I pesi delle unit\u00e0 di confronto sono elementi di insiemi ordinati (in questo caso interi), che possono essere confrontabili tra loro in termini di maggiore-minore. Un valore speciale <em>IGNORED<\/em> (0x0) significa che a quel livello di confronto l'unit\u00e0 corrispondente non partecipa al confronto. Il confronto delle stringhe pu\u00f2 ripetersi pi\u00f9 volte, utilizzando i pesi dei livelli corrispondenti. A ciascun livello, i pesi delle unit\u00e0 di confronto di due stringhe vengono confrontati sequenzialmente tra loro.<\/p>\n<p><\/p>\n<p>Nelle diverse implementazioni dell'algoritmo per le diverse tradizioni nazionali, i valori dei coefficienti possono variare, ma fa parte dello standard Unicode una tabella base dei pesi - <em>&quot;Default Unicode Collation Element Table&quot;<\/em> (<em>DUCET<\/em>). Vorrei sottolineare che impostare la variabile <em>LC_COLLATE<\/em> \u00e8 in effetti un'indicazione per la scelta della tabella dei pesi nella funzione di confronto delle stringhe.<\/p>\n<p><\/p>\n<p>I coefficienti di peso <em>DUCET<\/em> sono strutturati nel seguente modo:<\/p>\n<p><\/p>\n<ul>\n<li>al primo livello tutte le lettere vengono ridotte a un unico case, i segni diacritici vengono scartati, la punteggiatura (non tutta) viene ignorata;<\/li>\n<li>al secondo livello si considerano solo i segni diacritici;<\/li>\n<li>al terzo livello si considera solo il case;<\/li>\n<li>al quarto livello si considerano solo i segni di punteggiatura.<\/li>\n<\/ul>\n<p><\/p>\n<p>Il confronto avviene in pi\u00f9 passaggi: prima si confrontano i coefficienti di primo livello; se i pesi coincidono, si passa a un nuovo confronto con i pesi di secondo livello; poi, eventualmente, di terzo e quarto.<\/p>\n<p><\/p>\n<p>Il confronto termina quando nelle stringhe si trovano unit\u00e0 di confronto corrispondenti con pesi diversi. Le stringhe che hanno pesi uguali a tutti e quattro i livelli sono considerate uguali tra loro.<\/p>\n<p><\/p>\n<p>Questo algoritmo (con una serie di dettagli tecnici aggiuntivi) ha dato il nome al rapporto n. 10 - <em>&quot;Unicode Collation Algorithm&quot;<\/em> (<em>UCA<\/em>).<\/p>\n<p><\/p>\n<p>A questo punto, il comportamento della ordinazione dal nostro esempio diventa un po' pi\u00f9 chiaro. Sarebbe utile confrontarlo con lo standard Unicode.<\/p>\n<p><\/p>\n<p>Per testare le implementazioni <em>UCA<\/em> esiste un apposito <noindex><a rel=\"nofollow\" href=\"https:\/\/www.unicode.org\/Public\/UCA\/latest\/CollationTest.html\">test<\/a><\/noindex>, che utilizza <noindex><a rel=\"nofollow\" href=\"http:\/\/www.unicode.org\/Public\/UCA\/latest\/allkeys.txt\">un file di pesi<\/a><\/noindex>, realizzando <em>DUCET<\/em>. Nel file di pesi si possono trovare vari divertimenti. Ad esempio, ci sono l'ordine delle tessere del Mahjong e del domino europeo, cos\u00ec come l'ordine dei semi nel mazzo di carte (simbolo <em>1F000<\/em> e oltre). I semi delle carte sono disposti secondo le regole del bridge - PCHBT, e le carte in ogni seme seguono la sequenza 2,3\u2026 K.<\/p>\n<p><\/p>\n<p>Verifica manuale della correttezza dell'ordinamento delle stringhe secondo <em>DUCET<\/em> sarebbe piuttosto faticosa, ma, per nostra fortuna, esiste un'implementazione esemplare della libreria per lavorare con Unicode \u2014 &quot;<noindex><a rel=\"nofollow\" href=\"http:\/\/site.icu-project.org\/\">International Components for Unicode<\/a><\/noindex>&quot; (<em>ICU<\/em>).<\/p>\n<p><\/p>\n<p>Sul sito di questa libreria, sviluppata in <em>IBM<\/em>, ci sono pagine dimostrative, tra cui <noindex><a rel=\"nofollow\" href=\"http:\/\/demo.icu-project.org\/icu-bin\/collation.html\">la pagina dell'algoritmo di confronto delle stringhe<\/a><\/noindex>. Inseriamo le nostre stringhe di test con le impostazioni predefinite e, oh meraviglia, otteniamo un ordinamento russo perfetto.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Abakanov Michail;pittore\nJolkina Ella;gr\u00f9ista\nIvanov Andrej;idraulico\nIvanova Alla;avvocato<\/code><\/pre>\n<p><\/p>\n<p>A proposito, sul sito <em>ICU<\/em> si pu\u00f2 trovare un chiarimento sul funzionamento dell'algoritmo di confronto nella gestione della punteggiatura. Negli esempi <noindex><a rel=\"nofollow\" href=\"http:\/\/userguide.icu-project.org\/collation\/faq\">Collation FAQ<\/a><\/noindex> si ignorano l'apostrofo e il trattino.<\/p>\n<p><\/p>\n<p>Unicode ci ha aiutato, ma bisogner\u00e0 cercare le cause del comportamento strano <em>sort<\/em> in <em>Linux<\/em> da qualche altra parte.<\/p>\n<p><\/p>\n<h1 id=\"sortirovka-v-glibc\">Ordinamento in glibc<\/h1>\n<p><\/p>\n<p>Una rapida visione del codice sorgente dello strumento <em>sort<\/em> da <em>GNU Core Utils<\/em> ha mostrato che nella stessa utility la localizzazione si riduce alla stampa del valore attuale della variabile <em>LC_COLLATE<\/em> quando eseguita in modalit\u00e0 di debug:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$ sort --debug buhg.txt &gt; buhg.srt\nsort: utilizza le regole di ordinamento \u2018en_US.UTF8\u2019<\/code><\/pre>\n<p><\/p>\n<p>Il confronto delle stringhe viene effettuato dalla funzione standard <em>strcoll<\/em>, il che significa che tutto l'interessante si trova nella libreria <em>glibc<\/em>.<\/p>\n<p><\/p>\n<p>A <em>wiki<\/em> del progetto <em>glibc<\/em> il confronto delle stringhe \u00e8 dedicato <noindex><a rel=\"nofollow\" href=\"https:\/\/sourceware.org\/glibc\/wiki\/Locales#LC_COLLATE\">a un paragrafo<\/a><\/noindex>. Da questo paragrafo si pu\u00f2 capire che in <em>glibc<\/em> l'ordinamento si basa gi\u00e0 sull'algoritmo che conosciamo <em>UCA<\/em> (<em>The Unicode collation algorithm<\/em>) e\/o su uno standard simile <em>ISO 14651<\/em> (<em>Ordinamento e confronto delle stringhe internazionali<\/em>). Riguardo a quest'ultimo standard va notato che sul sito <noindex><a rel=\"nofollow\" href=\"https:\/\/standards.iso.org\/ittf\/PubliclyAvailableStandards\">standards.iso.org<\/a><\/noindex> <em>ISO 14651<\/em> \u00e8 ufficialmente dichiarato accessibile al pubblico, ma il link corrispondente porta a una pagina inesistente. Google restituisce diverse pagine con link a siti ufficiali che offrono l'acquisto di una copia elettronica dello standard per diverse centinaia di euro, ma nelle terza-quarta pagina dei risultati di ricerca si trovano anche collegamenti diretti a <em>PDF<\/em>. In generale, lo standard non si discosta praticamente da <em>UCA<\/em>, ma \u00e8 meno interessante da leggere poich\u00e9 non contiene esempi vividi delle peculiarit\u00e0 nazionali dell'ordinamento delle stringhe. <\/p>\n<p><\/p>\n<p>La informazione pi\u00f9 interessante su <em>wiki<\/em> \u00e8 stata un collegamento a <noindex><a rel=\"nofollow\" href=\"https:\/\/sourceware.org\/bugzilla\/show_bug.cgi?id=14095\">bug tracker<\/a><\/noindex> con una discussione sull'implementazione del confronto delle stringhe in <em>glibc<\/em>. Dalla discussione si pu\u00f2 scoprire che in <em>glibc<\/em> per il confronto delle stringhe viene utilizzata <em>ISO<\/em>la tabella <noindex><a rel=\"nofollow\" href=\"http:\/\/www.iso.org\/ittf\/ISO14651_2006_TABLE1_en.txt\">The Common Template Table<\/a><\/noindex> (<em>CTT<\/em>), il cui indirizzo pu\u00f2 essere trovato nell'allegato <em>A<\/em> dello standard <em>ISO 14651<\/em>. Tra il 2000 e il 2015 questa tabella in <em>glibc<\/em> non aveva un mantenitore e differiva notevolmente (perlomeno esternamente) dalla versione attuale dello standard. Dal 2015 al 2018 si \u00e8 svolta un'adattamento alla nuova versione della tabella e al momento avete la possibilit\u00e0 di incontrare nella vita reale sia la nuova variante della tabella (<em>CentOS 8<\/em>), sia la vecchia (<em>CentOS 7<\/em>). <\/p>\n<p><\/p>\n<p>Ora che abbiamo tutte le informazioni sull'algoritmo e sulle tabelle ausiliarie, possiamo tornare al problema originale e capire come ordinare correttamente le stringhe nella locale russa.<\/p>\n<p><\/p>\n<h1 id=\"iso-1465114652\">ISO 14651\/14652<\/h1>\n<p><\/p>\n<p>Il codice sorgente della tabella che ci interessa <em>CTT<\/em> \u00e8 presente nella maggior parte delle distribuzioni <em>Linux<\/em> nella directory <em>\/usr\/share\/i18n\/locales\/<\/em>. La tabella stessa si trova nel file <em>iso14651_t1_common<\/em>. Poi questo file con la direttiva <em>copy iso14651_t1_common<\/em> viene incluso nel file <em>iso14651_t1<\/em>, che, a sua volta, \u00e8 incluso nei file nazionali, compresi <em>en_US<\/em> e <em>ru_RU<\/em>. Nella maggior parte delle distribuzioni <em>Linux<\/em> tutti i file sorgente sono inclusi nella versione base, ma se non ci sono, sar\u00e0 necessario installare un pacchetto aggiuntivo dalla distribuzione.<\/p>\n<p><\/p>\n<p>La struttura del file <em>iso14651_t1<\/em> pu\u00f2 sembrare terribilmente prolisso, con regole non ovvie per la costruzione dei nomi, ma se ci si mette d\u2019impegno, tutto \u00e8 piuttosto semplice. La struttura \u00e8 descritta nello standard <em>ISO 14652<\/em>, una copia del quale pu\u00f2 essere scaricata dal sito <noindex><a rel=\"nofollow\" href=\"http:\/\/www.open-std.org\/JTC1\/SC22\/WG20\/docs\/n972-14652ft.pdf\">open-std.org<\/a><\/noindex>. Un'altra descrizione del formato del file pu\u00f2 essere letta in <noindex><a rel=\"nofollow\" href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/9699919799\/basedefs\/V1_chap07.html\">specifiche<\/a><\/noindex> <em>POSIX<\/em> di <em>OpenGroup<\/em>. In alternativa alla lettura dello standard, si possono studiare i testi sorgente della funzione <em>collate_read<\/em> in <em>glibc\/locale\/programs\/ld-collate.c<\/em>.<\/p>\n<p><\/p>\n<p>La struttura del file appare come segue:<\/p>\n<p><\/p>\n<p>Per impostazione predefinita, il simbolo \u00e8 utilizzato come carattere di escape, e la fine della riga dopo il simbolo # \u00e8 un commento. Entrambi i simboli possono essere sovrascritti, come fatto nella nuova versione della tabella:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">escape_char \/\ncomment_char %<\/code><\/pre>\n<p><\/p>\n<p>Nel file si incontreranno token nel formato <em>&lt;Uxxxx&gt;<\/em> o <em>&lt;Uxxxxxxxx&gt;<\/em> (dove <em>x<\/em> \u2014 cifra esadecimale). Questa \u00e8 la rappresentazione esadecimale dei punti di codice Unicode nella codifica <em>UCS-4<\/em> (<em>UTF-32<\/em>). Tutti gli altri elementi tra parentesi angolari (inclusi <em>&lt;Uxxxx_xxxx&gt;<\/em>, <em>&lt;2&gt;<\/em> e simili), sono considerati costanti di stringa semplici, prive di un significato speciale al di fuori del contesto.<\/p>\n<p><\/p>\n<p>Riga <em>LC_COLLATE<\/em> ci dice che di seguito iniziano i dati che descrivono il confronto delle stringhe.<\/p>\n<p><\/p>\n<p>Inizialmente vengono definiti i nomi per i pesi nella tabella di confronto e i nomi per le combinazioni di simboli. In generale, i due tipi di nomi appartengono a due entit\u00e0 diverse, ma nel file reale sono mescolati. I nomi dei pesi sono specificati dalla parola chiave <em>collating-symbol<\/em> (simbolo di confronto), poich\u00e9 durante il confronto i caratteri Unicode che hanno lo stesso peso saranno considerati simboli equivalenti.<\/p>\n<p><\/p>\n<p>La lunghezza complessiva della sezione nell'attuale revisione del file \u00e8 di circa 900 righe. Ho estratto esempi da diversi luoghi per dimostrare l'arbitrariet\u00e0 dei nomi e diversi tipi di sintassi.<\/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; % Il valore massimo garantito del simbolo. Mantieni alla fine di questo elenco\n...\ncollating-element &lt;U0413_0301&gt; da &quot;&lt;U0413&gt;&lt;U0301&gt;&quot;\ncollating-element &lt;U0413_0341&gt; da &quot;&lt;U0413&gt;&lt;U0341&gt;&quot;<\/code><\/pre>\n<p><\/p>\n<ul>\n<li><em>collating-symbol<\/em> registra la stringa <em>OSMANYA<\/em> nella tabella dei nomi dei pesi <\/li>\n<li><em>collating-symbol ..<\/em> registra una sequenza di nomi costituita da un prefisso <em>S<\/em> e un suffisso numerico esadecimale di <em>1D000<\/em> fino a <em>1D35F<\/em>.<\/li>\n<li><em>FFFF<\/em> in <em>collating-symbol<\/em> sembra un grande intero senza segno in notazione esadecimale, ma <em>&lt;SFFFF&gt;<\/em> \u00e8 semplicemente un nome che potrebbe sembrare come <em>&lt;VERYBIGVAL&gt;<\/em> <\/li>\n<li>nome <em>&lt;U0413&gt;<\/em> indica un punto di codice nella codifica <em>UCS-4<\/em><\/li>\n<li><em>collating-element &lt;U0413_0301&gt; da &quot;&lt;U0413&gt;&lt;U0301&gt;&quot;<\/em> registra un nuovo nome per una coppia di punti Unicode. <\/li>\n<\/ul>\n<p><\/p>\n<p>Quando i nomi dei pesi sono definiti, vengono impostati effettivamente i pesi. Poich\u00e9 nel confronto conta solo la relazione maggiore-minore, i pesi sono determinati da una semplice sequenza di elenco dei nomi. Prima vengono elencati i pesi &quot;leggeri&quot;, poi i pesi &quot;pesanti&quot;. Ricordo che a ogni simbolo Unicode vengono assegnati quattro pesi diversi. Qui sono riuniti in un'unica sequenza ordinata. Teoricamente, qualsiasi nome simbolico pu\u00f2 essere usato a uno dei quattro livelli, ma i commenti indicano che gli sviluppatori dividono mentalmente i nomi per livelli.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">% Assegnazione di pesi simbolici\n\n% Assegnazione di pesi di terzo livello\n\n\n\n\n...\n% Assegnazione di pesi di secondo livello\n\n % LINEA BASSA COMBINANTE\n % VIRGOLA COMBINANTE SOPRA\n % VIRGOLA ROVESCIATA COMBINANTE SOPRA\n...\n% Assegnazione di pesi di primo livello\n % TABULAZIONE ORIZZONTALE \n % CARRIAGE RETURN\n % TABULAZIONE VERTICALE\n...\n % LETTERA MINUSCOLA CYRILLIC DE\n % LETTERA MINUSCOLA CYRILLIC KOMI DE\n % LETTERA MINUSCOLA CYRILLIC DJE\n % LETTERA MINUSCOLA CYRILLIC KOMI DJE\n % LETTERA MINUSCOLA CYRILLIC GJE\n % LETTERA MINUSCOLA CYRILLIC ZE CON DISCENDENTE\n % LETTERA MINUSCOLA CYRILLIC IE\n % LETTERA MINUSCOLA CYRILLIC IE CON BREVE\n % LETTERA MINUSCOLA CYRILLIC IE UCRAINO\n % LETTERA MINUSCOLA CYRILLIC ZHE<\/code><\/pre>\n<p><\/p>\n<p>Finalmente, la tabella dei pesi.<\/p>\n<p><\/p>\n<p>La sezione dei pesi \u00e8 racchiusa in righe con parole chiave <em>order_start<\/em> e <em>order_end<\/em>. Ulteriori parametri <em>order_start<\/em> determinano in quale direzione vengono visualizzate le righe a ciascun livello di confronto. Di default viene utilizzato il parametro <em>forward<\/em>. Il corpo della sezione consiste in righe che contengono il codice del simbolo e i quattro pesi corrispondenti. Il codice del simbolo pu\u00f2 essere rappresentato dal simbolo stesso, dal punto codice o da un nome simbolico definito in precedenza. I pesi possono essere assegnati anche a nomi simbolici, punti codice o simboli stessi. Se vengono utilizzati punti codice o simboli, il loro peso corrisponde al valore numerico del punto codice (posizione nella tabella Unicode). I simboli non specificati esplicitamente (come comprendo) sono considerati assegnati alla tabella con un peso primario corrispondente alla posizione nella tabella Unicode. Il valore speciale del peso <em>IGNORE<\/em> significa che a quel livello di confronto il simbolo corrispondente viene ignorato.<\/p>\n<p><\/p>\n<p>Per dimostrare la struttura dei pesi ho scelto tre frammenti piuttosto evidenti:<\/p>\n<p><\/p>\n<ul>\n<li>simboli che vengono completamente ignorati<\/li>\n<li>simboli equivalenti al numero tre ai primi due livelli<\/li>\n<li>l'inizio dell'alfabeto cirillico, che non contiene segni diacritici, quindi ordinato principalmente nei primi e terzi livelli.<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"plaintext\">order_start forward;forward;forward;forward,position\n IGNORE;IGNORE;IGNORE;IGNORE % NULL (in 6429)\n IGNORE;IGNORE;IGNORE;IGNORE % INIZIO INTITOLAZIONE (in 6429)\n IGNORE;IGNORE;IGNORE;IGNORE % INIZIO TESTO (in 6429)\n...\n ;;; % DIGITO TRE\n ;;; % DIGITO TRE IN FORMATO LARGHI\n ;;; % DIGITO TRE TRA LETTERE\n ;;; % DIGITO TRE PUNTO FINALE\n ;;<FONT>; % DIGITO TRE BOLDO MATEMATICO\n...\n ;;; % LETTERA CIRILLICA PICCOLA A\n ;;; % LETTERA CIRILLICA MAIUSCOLA A\n ;;; % LETTERA CIRILLICA PICCOLA A CON BREVIO\n ;;; % LETTERA CIRILLICA PICCOLA A CON BREVIO\n...\n ;;; % LETTERA CIRILLICA PICCOLA BE\n ;;; % LETTERA CIRILLICA MAIUSCOLA BE\n ;;; % LETTERA CIRILLICA PICCOLA VE\n ;;; % LETTERA CIRILLICA MAIUSCOLA VE\n...\norder_end<\/code><\/pre>\n<p><\/p>\n<p>Ora possiamo tornare all'ordinamento degli esempi dall'inizio dell'articolo. La trappola si nasconde proprio in questa parte della tabella dei pesi:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">IGNORA;IGNORA;IGNORA; % SPAZIO\n IGNORA;IGNORA;IGNORA; % PUNTO ESCLAMATIVO\n IGNORA;IGNORA;IGNORA; % VIRGOLA\n...<\/code><\/pre>\n<p><\/p>\n<p>\u00c8 evidente che in questa tabella i segni di punteggiatura provengono dalla tabella <em>Rasterizzazione bit per bit o byte per byte<\/em> (incluso gli spazi) durante il confronto delle stringhe viene praticamente sempre ignorato. L'unica eccezione sono le stringhe che coincidono in tutto, tranne che per i segni di punteggiatura, che si trovano nelle posizioni corrispondenti. Le stringhe del mio esempio (dopo l'ordinamento) per l'algoritmo di confronto appaiono cos\u00ec:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">AbakanovMikhailpittore\nYolkinaEllaGiornata\nIvanovaAllamalz\nIvanovAndreiFabbro<\/code><\/pre>\n<p><\/p>\n<p>Tenendo conto che nella tabella dei pesi le lettere maiuscole in russo seguono quelle minuscole (al terzo livello <em>&lt;CAP&gt;<\/em> pi\u00f9 pesante di <em>&lt;MIN&gt;<\/em>), l'ordinamento appare assolutamente corretto.<\/p>\n<p><\/p>\n<p>Durante l'impostazione della variabile <em>LC_COLLATE=C<\/em> viene caricata una particolare tabella, che definisce il confronto byte per byte<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">static const uint32_t collseqwc[] =\n{\n  8, 1, 8, 0x0, 0xff,\n  \n  \/* tabella di 1\u00b0 livello *\/\n  6 * sizeof (uint32_t),\n  \/* tabella di 2\u00b0 livello *\/\n  7 * sizeof (uint32_t),\n  \/* tabella di 3\u00b0 livello *\/\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>Poich\u00e9 nel Unicode il punto codice \u0401 viene prima di \u0410, anche le stringhe vengono ordinate di conseguenza.<\/p>\n<p><\/p>\n<h1 id=\"tekstovye-i-dvoichnye-tablicy\">Tabelle testuali e binarie<\/h1>\n<p><\/p>\n<p>\u00c8 evidente che il confronto delle stringhe \u00e8 un'operazione estremamente comune, mentre l'analisi della tabella <em>CTT<\/em> \u00e8 una procedura piuttosto costosa. Per ottimizzare l'accesso alla tabella, viene compilata in forma binaria tramite il comando <em>localedef<\/em>.<\/p>\n<p><\/p>\n<p>Team <em>localedef<\/em> accetta come parametri un file con la tabella delle peculiarit\u00e0 nazionali (opzione <em>-i<\/em>), in cui tutti i caratteri sono rappresentati da punti Unicode, e un file di corrispondenza tra i punti Unicode e i caratteri di una particolare codifica (opzione <em>-f<\/em>). A seguito dell'esecuzione vengono creati file binari per la locale, con il nome specificato nell'ultimo parametro.<\/p>\n<p><\/p>\n<p><em>Glibc<\/em> supporta due formati di file binari: &quot;tradizionale&quot; e &quot;moderno&quot;.<\/p>\n<p><\/p>\n<p>Il formato tradizionale implica che il nome della locale sia il nome di una sottocartella in <em>\/usr\/lib\/locale\/<\/em>. In questa sottocartella sono memorizzati i file binari <em>LC_COLLATE<\/em>, <em>LC_CTYPE<\/em>, <em>LC_TIME<\/em> e cos\u00ec via. Il file <em>LC_IDENTIFICATION<\/em> contiene il nome formale della locale (che pu\u00f2 differire dal nome della cartella) e commenti.<\/p>\n<p><\/p>\n<p>Il formato moderno prevede la memorizzazione di tutte le locali in un unico archivio <em>\/usr\/lib\/locale\/locale-archive<\/em>, che viene mappato nella memoria virtuale di tutti i processi in uso <em>glibc<\/em>. Il nome della locale nel formato moderno subisce una certa canonizzazione: nei nomi delle codifiche rimangono solo cifre e lettere, convertite in minuscolo. Cos\u00ec <em>ru_RU.KOI8-R<\/em>, verr\u00e0 salvato come <em>ru_RU.koi8r<\/em>.<\/p>\n<p><\/p>\n<p>I file di input vengono cercati nella directory corrente e anche nelle directory <em>\/usr\/share\/i18n\/locales\/<\/em> e <em>\/usr\/share\/i18n\/charmaps\/<\/em> per i file <em>CTT<\/em> e per i file delle codifiche rispettivamente.<\/p>\n<p><\/p>\n<p>Ad esempio, il comando<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">localedef -i ru_RU -f MAC-CYRILLIC ru_RU.MAC-CYRILLIC<\/code><\/pre>\n<p><\/p>\n<p>compiler\u00e0 il file <em>\/usr\/share\/i18n\/locales\/ru_RU<\/em> utilizzando il file di codifica <em>\/usr\/share\/i18n\/charmaps\/MAC-CYRILLIC.gz<\/em> e salver\u00e0 il risultato in <em>\/usr\/lib\/locale\/locale-archive<\/em> con il nome <em>ru_RU.maccyrillic<\/em><\/p>\n<p><\/p>\n<p>Se imposti la variabile <em>LANG=en_US.UTF-8<\/em> allora <em>glibc<\/em> cercer\u00e0 file binari della locale nella seguente sequenza di file e directory:<\/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>Se la locale si presenta sia nei formati tradizionali che moderni, si dar\u00e0 priorit\u00e0 al formato moderno.<\/p>\n<p><\/p>\n<p>Puoi visualizzare l'elenco delle locali compilate con il comando <em>locale -a<\/em>.<\/p>\n<p><\/p>\n<h1 id=\"podgotovka-svoey-tablicy-sravneniya\">Preparazione della propria tabella di confronto<\/h1>\n<p><\/p>\n<p>Ora, armati delle conoscenze, puoi creare la tua tabella ideale di confronto delle stringhe. Questa tabella deve confrontare correttamente le lettere russe, inclusa la lettera \u0401, considerando anche la punteggiatura secondo la tabella <em>Rasterizzazione bit per bit o byte per byte<\/em>.<\/p>\n<p><\/p>\n<p>Il processo di preparazione della propria tabella di ordinamento consiste in due fasi: modifica della tabella dei pesi e compilazione in forma binaria con il comando <em>localedef<\/em>.<\/p>\n<p><\/p>\n<p>Per rendere la tabella di confronto facilmente modificabile con minimi costi di editing, nel formato <em>ISO 14652<\/em> sono previste sezioni per la modifica dei pesi della tabella esistente. La sezione inizia con la parola chiave <em>reorder-after<\/em> e l'indicazione della posizione, dopo la quale avviene la sostituzione. La sezione termina con la riga <em>reorder-end<\/em>. Se \u00e8 necessario correggere pi\u00f9 sezioni della tabella, si crea una sezione per ciascuna di esse.<\/p>\n<p><\/p>\n<p>Ho copiato le nuove versioni dei file <em>iso14651_t1_common<\/em> e <em>ru_RU<\/em> dal repository <em>glibc<\/em> nella mia directory home ~\/.local\/share\/i18n\/locales\/ e ho leggermente modificato la sezione <em>LC_COLLATE<\/em> in <em>ru_RU<\/em>. Le nuove versioni dei file sono completamente compatibili con la mia versione <em>glibc<\/em>. Se desideri utilizzare versioni precedenti dei file, dovrai cambiare i nomi simbolici e il punto in cui inizia la sostituzione nella tabella.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">LC_COLLATE\n% Copia il modello da 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; % SPAZIO\n&lt;U0021&gt; &lt;S0021&gt;;&lt;BASE&gt;;&lt;MIN&gt;&lt;U0021&gt; % PUNTO ESCLAMATIVO\n&lt;U0022&gt; &lt;S0022&gt;;&lt;BASE&gt;&lt;MIN&gt;&lt;U0022&gt; % VIRGOLETTE\n...\n&lt;U007D&gt; &lt;S007D&gt;;&lt;BASE&gt;&lt;MIN&gt;&lt;U007D&gt; % PARENTESE DEXTERA\n&lt;U007E&gt; &lt;S007E&gt;;&lt;BASE&gt;&lt;MIN&gt;&lt;U007E&gt; % TILDE\nreorder-end\nEND LC_COLLATE<\/code><\/pre>\n<p><\/p>\n<p>In realt\u00e0, bisognerebbe cambiare i campi in <em>LC_IDENTIFICATION<\/em> in modo che puntino alla locale <em>ru_MY<\/em>, ma nel mio esempio non \u00e8 stato necessario, poich\u00e9 ho escluso dalla ricerca le locali dell'archivio <em>locale-archive<\/em>.<\/p>\n<p><\/p>\n<p>Per <em>localedef<\/em> lavorava con i file nella mia cartella tramite la variabile <em>I18NPATH<\/em> si pu\u00f2 aggiungere una directory aggiuntiva per cercare i file di input, e la directory per salvare i file binari pu\u00f2 essere specificata come un percorso con le barre:<\/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> presuppone che in <em>LANG<\/em> si possano scrivere percorsi assoluti a directory con i file delle locali, che iniziano con una barra, ma <em>glibc<\/em> in <em>Linux<\/em> tutti i percorsi sono calcolati a partire dalla directory di base, che pu\u00f2 essere sovrascritta tramite la variabile <em>LOCPATH<\/em>. Dopo aver impostato <em>LOCPATH=~\/.local\/lib\/locale\/<\/em> tutti i file legati alla localizzazione verranno cercati solo nella mia cartella. L'archivio delle locali con la variabile impostata <em>LOCPATH<\/em> viene ignorato.<\/p>\n<p><\/p>\n<p>Ecco il test decisivo:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LANG=ru_MY.UTF-8 LOCPATH=~\/.local\/lib\/locale\/ sort buhg.txt\nAbakanov Michail;pittore\nJolkina Ella;gruista\nIvanov Andrei;fabbro\nIvanova Alla;avvocato<\/code><\/pre>\n<p><\/p>\n<p>Evviva! Ce l'abbiamo fatta!<\/p>\n<p><\/p>\n<h1 id=\"rabota-nad-oshibkami\">Lavoro sugli errori<\/h1>\n<p><\/p>\n<p>Ho gi\u00e0 risposto alle domande sulla ordinamento delle righe, sollevate all'inizio, ma restano un paio di domande sugli errori \u2014 visibili e invisibili.<\/p>\n<p><\/p>\n<p>Torniamo al compito originale.<\/p>\n<p><\/p>\n<p>E il programma <em>sort<\/em> e il programma <em>upgrade<\/em> utilizzano le stesse funzioni di confronto delle stringhe da <em>glibc<\/em>. Come ha fatto quindi <em>upgrade<\/em> a generare un errore di ordinamento su righe ordinate dal comando <em>sort<\/em> nella locale <em>en_US.UTF-8<\/em>? \u041e\u0442\u0432\u0435\u0442 \u043f\u0440\u043e\u0441\u0442: <em>sort<\/em> confronta l'intera stringa, mentre <em>upgrade<\/em> confronta solo la chiave, che per default \u00e8 l'inizio della stringa fino al primo carattere di spazio. Nel mio esempio ci\u00f2 ha portato a un messaggio di errore poich\u00e9 l'ordinamento delle prime parole nelle righe non corrispondeva all'ordinamento delle righe intere.<\/p>\n<p><\/p>\n<p>La locale <em>&quot;C&quot;<\/em> garantisce che le sottostringhe iniziali fino al primo spazio siano anch'esse ordinate nelle righe ordinate, ma questo nasconde solo l'errore. \u00c8 possibile trovare dati (persone con lo stesso cognome ma nomi diversi) che senza messaggi di errore darebbero un risultato errato nella fusione dei file. Se vogliamo che <em>upgrade<\/em> unisce le righe dei file per cognome e nome, il modo corretto \u00e8 specificare esplicitamente il delimitatore dei campi e ordinare sulla chiave, non sull'intera stringa. In questo caso, sia la fusione andr\u00e0 bene sia non ci saranno errori in nessuna locale:<\/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>Esempio eseguito con successo in codifica <em>CP1251<\/em> contiene un altro errore. Il fatto \u00e8 che in tutte le distribuzioni a me note <em>Linux<\/em> nei pacchetti manca la locale compilata <em>ru_RU.CP1251<\/em>. Se la locale compilata non viene trovata, allora <em>sort<\/em> utilizza silenziosamente il confronto byte per byte, come abbiamo osservato.<\/p>\n<p><\/p>\n<p>A proposito, c'\u00e8 un altro piccolo bug legato all'inaccessibilit\u00e0 delle locali compilate. Il comando <em>LOCPATH=\/tmp locale -a<\/em> restituir\u00e0 un elenco di tutte le locali in <em>locale-archive<\/em>, ma con la variabile impostata <em>LOCPATH<\/em> per tutti i programmi (incluso il <em>locale<\/em>) queste locali saranno inaccessibili.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">$&gt; LOCPATH=\/tmp locale -a | grep en_US\nlocale: Impossibile impostare LC_CTYPE sulla locale predefinita: nessun file o directory\nlocale: Impossibile impostare LC_MESSAGES sulla locale predefinita: nessun file o directory\nlocale: Impossibile impostare LC_COLLATE sulla locale predefinita: nessun file o directory\nen_US\nen_US.iso88591\nen_US.iso885915\nen_US.utf8\n\n$&gt; LC_COLLATE=en_US.UTF-8 sort --debug\nsort: utilizza le regole di ordinamento \u2018en_US.UTF-8\u2019\n\n$&gt; LOCPATH=\/tmp LC_COLLATE=en_US.UTF-8 sort --debug\nsort: utilizza un semplice confronto byte<\/code><\/pre>\n<p><\/p>\n<h1 id=\"zaklyuchenie\">Conclusione<\/h1>\n<p><\/p>\n<p>Se sei un programmatore abituato a pensare che le stringhe siano un insieme di byte, allora la tua scelta <em>LC_COLLATE=C<\/em>.<\/p>\n<p><\/p>\n<p>Se sei un linguista o un redattore di dizionari, ti conviene compilare la tua locale.<\/p>\n<p><\/p>\n<p>Se sei un normale utente, ti basta abituarti al fatto che il comando <em>ls -a<\/em> restituisce file che iniziano con un punto, mescolati con file che iniziano con una lettera, e <em>Midnight Commander<\/em>, che utilizza le proprie funzioni interne per l'ordinamento dei nomi, porta i file che iniziano con un punto all'inizio dell'elenco.<\/p>\n<p><\/p>\n<h1 id=\"ssylki\">Link<\/h1>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/unicode.org\/reports\/tr10\/\">Rapporto n. 10 algoritmo di ordinamento Unicode <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/www.unicode.org\/Public\/UCA\/latest\/allkeys.txt\">Pesi dei caratteri su 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 implementazione della libreria per l'elaborazione di Unicode di IBM. <\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/demo.icu-project.org\/icu-bin\/collation.html\">Test di ordinamento utilizzando <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\">Pesi dei caratteri 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\">Descrizione del formato del file con i pesi <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\">Discussione sulla comparazione delle stringhe in <em>glibc<\/em><\/a><\/noindex><\/p>\n<p>Fonte: <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.1.1 - 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\/it\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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\udd47Come il sort di Linux ordina le stringhe | ProHoster","description":"Introduzione Tutto \u00e8 iniziato con un breve script che doveva unire le informazioni sugli indirizzi e-mail dei dipendenti, ottenute dall'elenco degli utenti della mailing list, con.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/kak-linuxovskij-sort-sortiruet-stroki","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/83055","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=83055"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/83055\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=83055"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=83055"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=83055"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}