對於this question我創建了以下將代碼轉換爲UTF-8字符串的Lua代碼。有沒有更好的方法來做到這一點(在Lua 5.1+中)?在這種情況下,「更好」意味着「顯着更高效,或者優選更少的代碼行」。更優雅,更簡單的將代碼點轉換爲UTF-8的方法
注意:我並不真的要求這種算法的code review;我要求更好的算法(或內置庫)。
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.
我覺得自己好像應該是擺脫整個bytebits
預定義的表格和環只是爲了找到匹配條目的方式。從後面循環我可以連續%64
並添加128
以形成延續字節,直到值低於128,但我無法弄清楚如何優雅地生成要添加的前導碼。
編輯:這裏有一個稍微好一點的重構,速度優化。然而,這不是一個可以接受的答案,因爲算法仍然是基本相同的想法和大致相同數量的代碼。
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
試圖通過循環,我上面的最後評論描述了一個有缺陷的算法。例如,Unicode [代碼點0x10000](http://www.fileformat.info/info/unicode/char/10000/index.htm)需要UTF-8中的四個字節。在向右移位12位(兩個'/ 64')後,原始值下降到只有16位。似乎有些關於起始值,字節數和初始字節前導碼之間關係的硬編碼知識基本上是需要。 – Phrogz 2014-09-27 04:31:13