Per this question Ho creato il seguente codice Lua che converte un punto di codice Unicode in una stringa di caratteri UTF-8. C'è un modo migliore per farlo (in Lua 5.1+)? "Migliore" in questo caso significa "drasticamente più efficiente, o, preferibilmente, molto meno righe di codice".Un modo più elegante e più semplice per convertire il punto di codice in UTF-8
Nota: non sto davvero chiedendo un code review di questo algoritmo; Sto chiedendo un algoritmo migliore (o libreria integrata).
do
local bytebits = {
{0x7F,{0,128}},
{0x7FF,{192,32},{128,64}},
{0xFFFF,{224,16},{128,64},{128,64}},
{0x1FFFFF,{240,8},{128,64},{128,64},{128,64}}
}
function utf8(decimal)
local charbytes = {}
for b,lim in ipairs(bytebits) do
if decimal<=lim[1] then
for i=b,1,-1 do
local prefix,max = lim[i+1][1],lim[i+1][2]
local mod = decimal % max
charbytes[i] = string.char(prefix + mod)
decimal = (decimal - mod)/max
end
break
end
end
return table.concat(charbytes)
end
end
c=utf8(0x24) print(c.." is "..#c.." bytes.") --> $ is 1 bytes.
c=utf8(0xA2) print(c.." is "..#c.." bytes.") --> ¢ is 2 bytes.
c=utf8(0x20AC) print(c.." is "..#c.." bytes.") --> € is 3 bytes.
c=utf8(0xFFFF) print(c.." is "..#c.." bytes.") --> is 3 bytes.
c=utf8(0x10000) print(c.." is "..#c.." bytes.") --> is 4 bytes.
c=utf8(0x24B62) print(c.." is "..#c.." bytes.") --> is 4 bytes.
Mi sento come se ci dovrebbe essere un modo per sbarazzarsi di tutta la bytebits
tabella predefinita e loop di solo per trovare la voce corrispondente. A partire dal retro potrei continuamente %64
e aggiungere 128
per formare i byte di continuazione fino a un valore inferiore a 128, ma non riesco a capire come generare elegantemente il preambolo 0
/110
/1110
/11110
da aggiungere.
Edit: Ecco una rielaborazione leggermente migliore, con un'ottimizzazione della velocità. Questa non è una risposta accettabile, tuttavia, poiché l'algoritmo è ancora fondamentalmente la stessa idea e circa la stessa quantità di codice.
do
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
function utf8(decimal)
if decimal<128 then return string.char(decimal) end
local charbytes = {}
for bytes,vals in ipairs(bytemarkers) do
if decimal<=vals[1] then
for b=bytes+1,2,-1 do
local mod = decimal%64
decimal = (decimal-mod)/64
charbytes[b] = string.char(128+mod)
end
charbytes[1] = string.char(vals[2]+decimal)
break
end
end
return table.concat(charbytes)
end
end
Tentativo di eseguire il ciclo, il mio commento finale sopra descrive un algoritmo imperfetto. Ad esempio, Unicode [code point '0x10000'] (http://www.fileformat.info/info/unicode/char/10000/index.htm) richiede quattro byte in UTF-8. Dopo aver spostato a destra di 12 bit (due '/ 64') il valore originale è ridotto a solo 16. Sembra una conoscenza hard-coded sulla relazione tra il valore iniziale, il numero di byte e il preambolo del byte iniziale è fondamentalmente necessario. – Phrogz