对于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