對utf-8完全沒概念的可以看看我上一篇隨筆:簡單說說utf-8編碼格式
另外,還要知道string.sub 和 string.byte 的用法。
先上完整代碼:
local StringHelper = {} --[[ utf-8編碼規則 單字節 - 0起頭 1字節 0xxxxxxx 0 - 127 多字節 - 第一個字節n個1加1個0起頭 2 字節 110xxxxx 192 - 223 3 字節 1110xxxx 224 - 239 4 字節 11110xxx 240 - 247 可能有1-4個字節 --]]
function StringHelper.GetBytes(char) if not char then
return 0
end
local code = string.byte(char) if code < 127 then
return 1
elseif code <= 223 then
return 2
elseif code <= 239 then
return 3
elseif code <= 247 then
return 4
else
-- 講道理不會走到這里^_^
return 0
end
end
function StringHelper.Sub(str, startIndex, endIndex) local tempStr = str local byteStart = 1 -- string.sub截取的開始位置
local byteEnd = -1 -- string.sub截取的結束位置
local index = 0 -- 字符記數
local bytes = 0 -- 字符的字節記數
startIndex = math.max(startIndex, 1) endIndex = endIndex or -1
while string.len(tempStr) > 0 do
if index == startIndex - 1 then byteStart = bytes+1; elseif index == endIndex then byteEnd = bytes; break; end bytes = bytes + StringHelper.GetBytes(tempStr) tempStr = string.sub(str, bytes+1) index = index + 1
end
return string.sub(str, byteStart, byteEnd) end
基本思路:
之所以要自己寫一個截取函數,是因為lua的庫函數string.sub實際是字節的截取函數。
uft-8編碼格式中,大部分中文是3個字節表示的,數字和字母等是一個字節的,還有某些國家的語言是2字節的,直接用string.sub就可能截出亂碼來,因為不確定要截多少個字節。
所以,
定義一個GetBytes函數,獲取字符的字節數(根據首個字節的高位標記,判斷是幾字節的字符)
然后不斷后移,記錄字節數和字符數。
如上圖,假設要取字符3-4,那么應該從第3個字符的第一個字節取到第4個字最后一個字節
即:
當前字符數為截取的起始字符(startIndex)前一個位置時,說明從下一個字節開始截取字符串 即 index == startIndex - 1 時 byteStart = bytes+1
當前字符數為截取的終止字符(endIndex)時,說明要截取的字符串到此為止 即 index == endIndex 時 byteEnd = bytes
用 string.sub(str, byteStart, byteEnd) 就能截取byteStart 到 byteEnd 的字節
測試代碼:
str = "中1文*a字符串勉強します"; print(StringHelper.Sub(str, 3, 4)) print(StringHelper.Sub(str, 1, 4)) print(StringHelper.Sub(str, 8)) print(StringHelper.Sub(str, 2, 12))
測試結果: