Lua 原生字串操作以位元組為單位,無法正確處理 UTF-8 多位元組字元。提供兩個實用函式:utfstrlen 計算字元數,GetShortName 依字元寬度截斷並補上省略號。
function utfstrlen(str)
local len = #str
local left = len
local cnt = 0
local arr = {0, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}
while left ~= 0 do
local b = string.byte(str, -left)
local i = #arr
while arr[i] do
if b >= arr[i] then left = left - i; break end
i = i - 1
end
cnt = cnt + 1
end
return cnt
end
原理:依首位元組最高位判斷字元長度(1~4 位元組),逐字元前進計數。
function GetShortName(sName, nMaxCount, nShowCount)
if not sName or not nMaxCount then return end
nShowCount = nShowCount or (nMaxCount - 3)
local tCode, tName = {}, {}
local nLen = #sName
local nWidth = 0
for i = 1, nLen do
local b = string.byte(sName, i)
local byteCount = 0
if b > 0 and b <= 127 then byteCount = 1
elseif b >= 192 and b < 223 then byteCount = 2
elseif b >= 224 and b < 239 then byteCount = 3
elseif b >= 240 and b < 247 then byteCount = 4 end
local char = byteCount > 0 and string.sub(sName, i, i + byteCount - 1)
if byteCount == 1 then
nWidth = nWidth + 1
table.insert(tName, char); table.insert(tCode, 1)
elseif byteCount > 1 then
nWidth = nWidth + 2 -- 中文視為雙寬
table.insert(tName, char); table.insert(tCode, 2)
end
if byteCount > 0 then i = i + byteCount - 1 end
end
if nWidth > nMaxCount then
local out, w = "", 0
for i = 1, #tName do
out = out .. tName[i]
w = w + tCode[i]
if w >= nShowCount then break end
end
return out .. "..."
end
return sName
end
local str = "Hello世界"
print(utfstrlen(str)) -- 7
print(GetShortName(str, 8, 5)) -- Hello世...
print(GetShortName(str, 10)) -- Hello世界 (未超寬)
nMaxCount:最大顯示寬度(中文計 2,英文計 1)。nShowCount:截斷前保留寬度,預留 3 寬度給 ...。utf8 標準庫 (utf8.len, utf8.offset) 簡化實作。