Visualizzazione post con etichetta ASCII. Mostra tutti i post
Visualizzazione post con etichetta ASCII. Mostra tutti i post

giovedì 12 marzo 2020

Importazione dei dati da un file di solo testo

Abbiamo visto in precedenza come sono organizzati i dati in un file .csv, il formato raccomandato per R, e abbiamo visto che un file .csv è un semplice file di testo [1].

Se aprite con un editor di testo il file importa_csv.csv (se non l'avete già scaricato, trovate come farlo nella pagina Datiquesto è quello che vi appare:

id;sesso;anni;peso_kg;altezza_m
MT;M;69;76;1,78
GF;F;56;63;
MC;F;53;71;1,60
SB;M;28;73;1,78
FE;F;61;54;1,54
AB;M;46;92;1,84
RF;F;31;81;1,56

Se ci pensate bene, però, oltre a lettere, numeri, caratteri di interpunzione e qualche altro carattere accessorio, o, più tecnicamente, oltre a una serie di caratteri ASCII stampabili [2] nel testo è incluso un "a capo" (o se preferite un ↵ Invio) che segna il passaggio da una riga alla successiva, o, in altre parole, che separa un record dal successivo: ed è chiaro che in qualche modo questo carattere, uno dei caratteri non stampabili (detti anche caratteri di controllo) del codice ASCII, deve essere stato codificato nel file.

Che proprio questo sia il caso è dimostrabile aprendo il file con un editor di testo che sia in grado di mostrare, oltre ai caratteri ASCII, anche i caratteri di controllo contenuti nel file, uno dei quali è appunto il carattere di "a capo".

Per esempio se aprite il file importa_csv.csv con PSPad [3] ed attivate nel menù Visualizza la funzione Modalità esadecimale vedete questo:

















Sulla destra compaiono i caratteri ASCII contenuti nel file, sulla sinistra compare il valore esadecimale corrispondente. Sulla destra vedete ricorrere al termine di ogni record una sequenza di due punti consecutivi (..), sulla sinistra vedete che ad essi corrisponde la sequenza 0D0A che è la rappresentazione esadecimale di CR (Carriage Return) e di LF (Line Feed) cioè rispettivamente del ritorno di carrello a inizio riga (0D esadecimale) e del passaggio ad una nuova riga (0A esadecimale) che l'informatica ha ereditato dalla macchina da scrivere


Questi due caratteri ASCII l'editor di testo li interpreta come caratteri di controllo, cioè come caratteri che non devono essere rappresentati, ma che indicano una azione da compiere: passare a una nuova riga di testo inserendo un "a capo" (un ↵ Invio) [4].

R è ovviamente in grado di interpretare correttamente i caratteri di controllo, infatti se nella Console di R incollate questa riga di codice

mydatacsv <- read.table("C:/Rdati/importa_csv.csv", header=TRUE, sep=";", dec=",")

e premete ↵ Invio per importare i dati dal file .csv, quindi digitate

mydatacsv

e premete ↵ Invio per mostrare i dati importati, ottenete questo risultato:

> mydatacsv <- read.table("C:/Rdati/importa_csv.csv", header=TRUE, sep=";", dec=",")
> mydatacsv
  id sesso anni peso_kg altezza_m

1 MT     M   69      76      1.78
2 GF     F   56      63        NA
3 MC     F   53      71      1.60
4 SB     M   28      73      1.78
5 FE     F   61      54      1.54
6 AB     M   46      92      1.84
7 RF     F   31      81      1.56

(NA indica un dato mancante).

Ma con R è possibile un'altra cosa: si possono codificare i caratteri di controllo in chiaro, come viene fatto nel file importa_txt.txt che contiene gli stessi dati e che, aperto con un editor di testo, così vi appare:

MT;M;69;76;1,78\nGF;F;56;63;\nMC;F;53;71;1,60\nSB;M;28;73;1,78\nFE;F;61;54;1,54\nAB;M;46;92;1,84\nRF;F;31;81;1,56


Da notare che nel file importa_txt.txt rispetto al corrispondente file .csv:
i caratteri di controllo CR e LF (nascosti nel file .csv) sono stati sostituiti con i caratteri (in chiaro) \n ove la barra rovesciata \ (o backslash) indica a R la presenza di un carattere di controllo e n sta per New Line (“passa a una nuova riga”);
→ il file non contiene i nomi delle variabili, che devono essere specificati nella funzione read.table() mediante l'argomento col.names;
l'ultimo carattere nel file deve essere un ↵ Invio (cioè un "a capo") che in questo caso deve immediatamente seguire il 6 del dato finale 1,56.

Il file importa_txt.txt potete scaricarlo e installarlo nella cartella C:\Rdati seguendo le istruzioni fornite nella pagina Dati. Ora copiate nella Console di R questa riga di codice

mydatatxt <- read.table("c:/Rdati/importa_txt.txt", header=TRUE, col.names=c("id", "sesso", "anni", "peso_kg", "altezza_m"), sep=";", dec=",", allowEscapes=TRUE)

e premete ↵ Invio per importare i dati, quindi digitate

mydatatxt

e premete ↵ Invio per visualizzare i dati importati. 

Da notare che l'argomento allowEscapes=TRUE fa si che R interpreti la  sequenza \n come un carattere di controllo (un ↵ Invio) e non come due semplici caratteri di testo. Come vedete il risultato ottenuto

> mydatatxt <- read.table("c:/Rdati/importa_txt.txt", header=TRUE, col.names=c("id","sesso","anni","peso_kg","altezza_m"), sep=";", dec=",", allowEscapes=TRUE)
> mydatatxt
  id sesso anni peso_kg altezza_m

1 MT     M   69      76      1.78
2 GF     F   56      63        NA
3 MC     F   53      71      1.60
4 SB     M   28      73      1.78
5 FE     F   61      54      1.54
6 AB     M   46      92      1.84
7 RF     F   31      81      1.56

è identico a quello ottenuto importando i dati del file .csv.

Il senso di tutto ciò? Semplice. Guardate il set di dati Galton, si tratta di 928 righe di dati, ciascuna corrispondente a un record, più una riga per i nomi delle variabili. Se invece di un file .csv impiegate un file .txt separando i record con \n potete compattare i dati in un numero enormemente inferiore di righe, cosa che ad esempio rende possibile inserire un numero così elevato di record in un testo.


----------


Addendum

Se siete arrivati fino a qui, avete certamente notato che nel post manca una cosa fondamentale: un metodo semplice per generare un file di testo nel quale i caratteri di controllo nascosti CR e LF sono sostituiti con un \n riportato in chiaro.

In effetti ci sono programmi che consentono di effettuare la sostituzione online: alcuni forniscono come risultato un file nel quale la sequenza di caratteri di controllo CRLF è automaticamente sostituita con \n [5], altri forniscono come risultato un file nel quale detta sequenza è sostituita con uno spazio vuoto [6], che successivamente può essere sostituito manualmente con \n.

Qui vediamo come effettuare la sostituzione con la seconda modalità, che è la più semplice, impiegando R e un comune editor di testo.

Scaricate dal CRAN e installate il pacchetto stringr [7]. Quindi copiate e incollate nella Console di R questo script e premete ↵ Invio

# SALVA I DATI IN UN FILE DI TESTO ELIMINANDO I CARATTERI DI CONTROLLO CR e LF
#
library(stringr) # carica il pacchetto
mydata <- readLines("C:/Rdati/importa_csv.csv") # legge il file
newdata <- mydata[-c(1)] # elimina la prima riga che contiene i nomi delle variabili
mystring <- str_c(newdata, collapse=" ") # concatena i record in un'unica stringa separandoli con uno spazio
write(mystring, file="C:/Rdati/temp.txt") # salva la stringa in un file di testo

Va subito precisato che il messaggio che vi comparirà

Warning message:
In readLines("C:/Rdati/importa_csv.csv") :
incomplete final line found on 'C:/Rdati/importa_csv.csv'

non indica un errore, ma è un semplice avvertimento che segnala la mancanza della sequenza CRLF (cioè di un ↵ Invio) alla fine del file: i dati sono importati correttamente, come potete constatare digitando mydata.

Nelle cinque righe di codice, nell'ordine:
→ con la funzione library() viene caricato il pacchetto stringr;
→ con readLine(s) un normale file .csv (vedere il post Importazione dei dati da un file .csv) viene importato riga per riga;
→ con [-c(1)] viene eliminata la prima riga, quella che contiene i nomi delle variabili;
→ con la funzione str_c() del pacchetto stringr le righe (record) del file importate sono concatenate in un'unica stringa separando l'una dall'altra con uno spazio (collapse=" ") ;
la stringa che risulta dal concatenamento viene salvata nel file C:/Rdati/temp.txt.

Digitate mydata, poi newdata e infine mystring per visualizzare la progressiva trasformazione dei dati.

Infine, impiegando un editor di testo come il Blocco note di Windows:
aprite il file C:/Rdati/temp.txt
utilizzate la funzione Modifica > Sostituisci per sostituire lo spazio vuoto con i caratteri \n















A questo punto ricordatevi che l'ultimo carattere del file deve essere un ↵ Invio (cioè un "a capo") che dovete inserire manualmente immediatamente dopo il 6 del dato finale 1,56. Poi salvate il risultato nel file definitivo, denominato a piacere ma possibilmente per coerenza con estensione .txt, e avrete finalmente un file di dati di R in formato testo come questo

MT;M;69;76;1,78\nGF;F;56;63;\nMC;F;53;71;1,60\nSB;M;28;73;1,78\nFE;F;61;54;1,54\nAB;M;46;92;1,84\nRF;F;31;81;1,56


che impiega come separatore di record la sequenza di caratteri \n codificata in chiaro, e che può essere importato in R mediante la funzione read.table() impiegando l'argomento allowEscapes=TRUE.

Supponendo che abbiate denominato questo file C:\Rdati\ilmiofile_txt.txt se copiate nella Console di R questa riga di codice

mydatatxt <- read.table("c:/Rdati/ilmiofile_txt.txt", header=TRUE, col.names=c("id", "sesso", "anni", "peso_kg", "altezza_m"), sep=";", dec=",", allowEscapes=TRUE)

e premete ↵ Invio per importare i dati, quindi digitate

mydatatxt

e premete ↵ Invio per visualizzare i dati importati, potete verificare che il tutto ha funzionato correttamente e che pertanto siete in grado, al bisogno, da un lato di generare un file di testo con i caratteri di controllo in chiaro, e dall'altro lato di importarne i dati in R.


----------



[3] PSPad freeware editor.
https://www.pspad.com/it/

[4] In realtà esistono tre modi per codificare un "a capo" (un ↵ Invio), e dipendono dal sistema operativo impiegato:
 CRLF (\r\n): usato da MS-DOS e Microsoft Windows, al quale si fa qui riferimento;
 LF (\n): usato da sistemi Unix, Linux e Apple (GNU/Linux, Mac OS X e macOS);
 CR (\r): usato da Commodore e Apple (Mac OS fino alla versione 9 inclusa).

[5] Remove/Replace all line breaks of a text.
https://gillmeister-software.com/online-tools/text/remove-line-breaks.aspx

[6] Convert Newlines to Spaces.
https://www.browserling.com/tools/newlines-to-spaces

[7] Vedere il manuale di riferimento del pacchetto Package 'stringr'.
https://cran.r-project.org/web/packages/stringr/stringr.pdf

martedì 20 novembre 2018

Codifica dei caratteri ASCII, ANSI, Unicode (UTF)

ASCII – che in inglese si pronuncia æski (æ come in fat, s come in sorry, k come in car, i come in happy), ma in italiano viene pronunciato aschi o anche asci – è l'acronimo di American Standard Code for Information Interchange ed è il primo standard introdotto nella codifica dei caratteri di scrittura nel campo dell'IT (Information Techology). 

Il codice ASCII è definito nella norma ISO/IEC 646 - Information technology - ISO 7-bit coded character set for information interchange [1].

Nel codice ASCII i caratteri sono codificati con 7 bit cosa che permette di codificare 27 = 128 caratteri numerati da 0 a 127I concetti alla base dello standard sono semplici e pratici:
→ codificare i caratteri di controllo ovvero i comandi necessari per gestire da remoto una stampante (originariamente una telescrivente);
→ codificare i caratteri stampabili – lettere, numeri, segni di interpunzione e simboli – di impiego più frequente nella scrittura di un testo.

I caratteri da 0 a 31 sono caratteri di controllo e non sono stampabili. Il carattere 32 corrisponde a uno spazio. I caratteri da 33 a 126 sono caratteri stampabili. Il carattere 127 corrisponde a Delete (ed è equivalente a Backspace).

Questo è il set di caratteri ASCII standard altrimenti noto come set di caratteri ASCII di base:

Codice Simbolo Codice Carattere Codice Carattere Codice Carattere
0 NUL 32
64 @ 96 `
1 SOH 33 ! 65 A 97 a
2 STX 34 " 66 B 98 b
3 ETX 35 # 67 C 99 c
4 EOT 36 $ 68 D 100 d
5 ENQ 37 % 69 E 101 e
6 ACK 38 & 70 F 102 f
7 BEL 39 ' 71 G 103 g
8 BS 40 ( 72 H 104 h
9 TAB 41 ) 73 I 105 i
10 LF 42 * 74 J 106 j
11 VT 43 + 75 K 107 k
12 FF 44 , 76 L 108 l
13 CR 45 - 77 M 109 m
14 SO 46 . 78 N 110 n
15 SI 47 / 79 O 111 o
16 DLE 48 0 80 P 112 p
17 DC1 49 1 81 Q 113 q
18 DC2 50 2 82 R 114 r
19 DC3 51 3 83 S 115 s
20 DC4 52 4 84 T 116 t
21 NAK 53 5 85 U 117 u
22 SYN 54 6 86 V 118 v
23 ETB 55 7 87 W 119 w
24 CAN 56 8 88 X 120 x
25 EM 57 9 89 Y 121 y
26 SUB 58 : 90 Z 122 z
27 ESC 59 ; 91 [ 123 {
28 FS 60 < 92 \ 124 |
29 GS 61 = 93 ] 125 }
30 RS 62 > 94 ^ 126 ~
31 US 63 ? 95 _ 127 

Questa è la versione sintetica della tabella precedente, con i soli caratteri ASCII di base stampabili:

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

Di fatto il set di caratteri ASCII di base riflette il modo in cui i caratteri sono scritti su (e possono essere riletti da) un foglio di carta scritto con una macchina da scrivere, impiegando un set di caratteri/codice universalmente riconosciuto. Non solo: della macchina da scrivere il codice ASCII conserva, ad esempio, il comando LF (Line Feed) che fa avanzare il foglio alla riga successiva, e il comando CR (Carriage Return) che riporta il carrello della macchina da scrivere (virtuale) all'inizio della riga. Anche se la macchina da scrivere è stato oramai da decenni sostituita da PC, word processor e stampante, è da questa che sono derivati i concetti e questo standard minimo di base.

Gli altri set di caratteri che vediamo ora hanno progressivamente esteso il set di caratteri ASCII di base con set di caratteri aggiuntivi, con l'obiettivo di includere tutti i caratteri di tutte le lingue (cosa inimmaginabile via hardware, con un dispositivo meccanico come la macchina da scrivere, ma senza sostanziali problemi via software).

Il primo nato allo scopo di estendere il set di caratteri ASCII di base è stato il set di caratteri ANSI (acronimo di American National Standard Institute) nel quale i caratteri sono codificati con 8 bit cosa che permette di codificare 28 = 256 caratteri numerati da 0 a 255. Il set di caratteri ANSI include due sottoinsiemi:
→ il set di caratteri ASCII di base (caratteri numerati da 0 a 127) visto sopra;
→ il set di caratteri ASCII esteso (caratteri numerati da 128 a 255). 

Purtroppo per i caratteri da 128 a 255 (set di caratteri ASCII estesonon si è stabilito subito un accordo e questo ha determinato la presenza di differenze tra il set di caratteri a 8 bit Windows 1252 (che viene denominato impropriamente ANSI e che è ampiamente utilizzato) e il set di caratteri ISO-8859-1 anch'esso a 8 bit: i due infatti codificano in modo differente i caratteri da 128 a 159.

Dati questo iniziale incidente di percorso, la vitale importanza di una codifica univoca dei caratteri e il numero elevato di caratteri da codificare (si pensi ad esempio al cirillico, al greco, all'aramaico, all'ebraico e al numero di ideogrammi necessari per codificare i testi in Cinese, Giapponese e Coreano) è nato quindi Unicode, un consorzio no-profit privato al quale partecipano tutte le principali aziende di informatica, con lo scopo di assegnare ad ogni carattere impiegato per la scrittura un numero univoco indipendente dalla lingua, dalla piattaforma informatica e dal software impiegati [2].

Gli standard Unicode sono identificati dalla sigla UTF (Unicode Transformation Format) seguita da un numero progressivo di versione. Dal 1991 il Consorzio Unicode ha sviluppato gli standard in parallelo con la norma ISO/IEC 10646 che definisce l'Universal Coded Character Set (UCS). Entrambi hanno lo stesso repertorio di caratteri, con gli stessi numeri: fortunatamente, e saggiamente, Unicode e ISO hanno deciso di normare congiuntamente in modo identico questo aspetto di base e così delicato della comunicazione.

Di fatto Unicode è oggi il riferimento ufficiale per la codifica standard dei caratteri – per definizione in linea con la normativa ISO –  e include:
→ il set di caratteri ASCII di base – denominato Basic Latin [3]
→ il set di caratteri ASCII esteso – denominato Latin-1 Supplement [4]
accanto agli altri set di caratteri che nel frattempo sono stati sviluppati, e continuano ad essere aggiornati, per coprire tutte le lingue del mondo [5] .

Attualmente il più estesamente impiegato è lo standard UTF-8: alla data di pubblicazione di questo post la maggior parte delle pagine web sono state realizzate impiegando la codifica dei caratteri prevista da questo standard, che è stato rilasciato nel 2015.

Le successive versioni, insieme a tutte quelle passate, le potete trovare sul sito di Unicode [6].


----------

[1] ISO/IEC 646.
https://en.wikipedia.org/wiki/ISO/IEC_646

[2] The Unicode Consortium.
https://home.unicode.org/

[3] C0 Controls and Basic Latin.
https://www.unicode.org/charts/PDF/U0000.pdf

[4] C1 Controls and Latin-1 Supplement.
https://www.unicode.org/charts/PDF/U0080.pdf

[5] Unicode Character Code Charts.
https://www.unicode.org/charts/

[6] Enumerated Versions of The Unicode® Standard.
https://www.unicode.org/versions/enumeratedversions.html