2015-04-24 10 views
5

È possibile leggere un carattere UTF-8 dal file?Lua - leggi un carattere UTF-8 dal file

file: read (1) restituisce caratteri strani invece, quando lo stampo.

function firstLetter(str) 
    return str:match("[%z\1-\127\194-\244][\128-\191]*") 
end 

La funzione restituisce un carattere UTF-8 da stringa str. Ho bisogno di leggere un carattere UTF-8 in questo modo, ma dal file di input (non voglio leggere determinati file nella memoria - tramite file: read ("* all"))

La domanda è molto simile a questo posta: Extract the first letter of a UTF-8 string with Lua

+1

Un modo piuttosto semplice ma di sicuro non molto popolare è quello di "analizzare effettivamente i byte (1..6) e convertirli in un valore UTF-32". L'uso di UTF-32 può rendere le cose più facili in alcuni casi, a seconda di cosa farai. – BitTickler

+0

Esegui cosa fa quella funzione mentre legge manualmente un personaggio alla volta? Anche se questo ti finirà per aver letto un altro personaggio di cui avevi bisogno quindi dovrai riavvolgere. –

+0

ho intenzione di creare un correttore di tipografia (che può leggere anche caratteri cechi), quindi leggerò il file di input, troverò gli errori e lo correggerò. Ma è impossibile lavorare con (per i personaggi sconosciuti di Lua). Testo originale: ľúbozvučně řeřicha čučoridka ľaľia Testo che è stato letto da Lua (in Zero Brane Studio): [link] (http://i.imgur.com/PcorbzP.png) quando confronto il primo carattere da entrambi, non corrisponde a – Hrablicky

risposta

1
function read_utf8_char(file) 
    local c1 = file:read(1) 
    local ctr, c = -1, math.max(c1:byte(), 128) 
    repeat 
    ctr = ctr + 1 
    c = (c - 128)*2 
    until c < 128 
    return c1..file:read(ctr) 
end 
+2

Questa è una risposta esatta alla domanda ma non una buona risposta senza una spiegazione. –

+0

@TomBlodget - Il tuo giudizio non è corretto: come vedi, nessuno ha chiesto chiarimenti sulla mia risposta. Sembra che tu tratti le persone come creature stupide, quindi tutto deve essere spiegato nei dettagli. Al contrario, penso che le persone siano abbastanza intelligenti. Certo, sono pronto a dare spiegazioni extra se qualcuno mi dirà quale parte della mia risposta non è chiara per lui. –

+0

@TomBlodget - "Il tuo pubblico è più intelligente di quanto immagini." (una citazione da [13 Suggerimenti di scrittura da Chuck Palahniuk] (http://litreactor.com/essays/chuck-palahniuk/stocking-stuffers-13-writing-tips-from-chuck-palahniuk), suggerimento n. 2) –

0

Hai bisogno di leggere i caratteri in modo che la stringa che si sta corrispondendo sempre ha quattro o più di essi (che vi permetterà di applicare la logica dalla risposta si fa riferimento). Se dopo la corrispondenza e la rimozione di un carattere UTF-8 la lunghezza è len, viene quindi letto dal file 4-len caratteri.

ZeroBrane Studio sostituisce caratteri UTF-8 non validi con il carattere [SYN] quando viene stampato sul pannello Output (come si vede nello screenshot). This blogpost descrive la logica alla base del rilevamento di caratteri UTF-8 non validi (in Lua) e della loro gestione in ZeroBrane Studio.

0

In UTF-8 codifica il numero di byte adottate per un carattere è determinato dal primo byte di questo personaggio, secondo la tabella seguente (tratto da RFC 3629:

Char. number range |  UTF-8 octet sequence 
    (hexadecimal) |    (binary) 
--------------------+--------------------------------------------- 
0000 0000-0000 007F | 0xxxxxxx 
0000 0080-0000 07FF | 110xxxxx 10xxxxxx 
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 

Se il bit più alto di il primo byte è "0", quindi il carattere ha un solo byte Se i bit più alti sono "110", il carattere ha 2 byte e così via

Quello che puoi fare è leggere un byte dal file e determinare quanti byte di continuazione è necessario leggere per il carattere UTF-8 completo:

function get_one_utf8_character(file) 

    local c1 = file:read(1) 
    if not c1 then return nil end 

    local ncont 
    if  c1:match("[\000-\127]") then ncont = 0 
    elseif c1:match("[\192-\223]") then ncont = 1 
    elseif c1:match("[\224-\239]") then ncont = 2 
    elseif c1:match("[\240-\247]") then ncont = 3 
    else 
    return nil, "invalid leading byte" 
    end 

    local bytes = { c1 } 
    for i=1,ncont do 
    local ci = file:read(1) 
    if not (ci and ci:match("[\128-\191]")) then 
     return nil, "expected continuation byte" 
    end 
    bytes[#bytes+1] = ci 
    end 

    return table.concat(bytes) 
end