Lua 字符串插值
Lua 的格式化字符串又臭又長(zhǎng)机久,不僅需要輸入格式化模式,還存在參數(shù)冗余赔嚎,比如:
print(string.format('Hi! %s am %s, %s am from %s', 'I', 'DoooReyn', 'I', 'China'))
-- output: Hi! I am DoooReyn, I am from China
于是就想到膘盖,在 Python 中,格式化字符串可以使用多種形式尤误,其中一種是字符串插值侠畔,就解決了這個(gè)問(wèn)題,如下:
name = "DoooReyn"
"I am {name}".format(name=name)
# output
# I am DoooReyn损晤,我來(lái)自中國(guó)
于是就想 Lua 可不可以這么搞软棺。那么就來(lái)嘗試一下吧:
- 首先,定義下提取變量的規(guī)范:
{var}
尤勋,模式匹配為:{%w+}
- 接下來(lái)喘落,準(zhǔn)備解析格式化字符串,可以使用 Lua 的
string.gsub
- 最后最冰,提取到變量名之后瘦棋,進(jìn)行替換操作即可
于是得到:
function string.interpolate(fmt, keys)
local ret =
string.gsub(
fmt,
'{%w+}',
function(c)
local key = string.match(c, "(%w+)")
-- 添加數(shù)字索引支持
key = tonumber(key) or key
local val = keys[key]
-- 轉(zhuǎn)化為字符串
val = tostring(val == nil and '' or val)
return val
end
)
return ret
end
測(cè)試一下:
print(string.interpolate('Hi! {who} am {name}, {who} am from {from}', {who = 'I', name = 'DoooReyn', from = 'China'}))
-- output: Hi! I am DoooReyn, I am from China
print(string.interpolate('Hi! {1} am {2}, {1} am from {3}', {'I', 'DoooReyn', 'China'}))
-- output: Hi! I am DoooReyn, I am from China
完美!
后記
本來(lái)還想到另外一種做法锌奴,使用 debug.getlocal
獲取調(diào)用 string.interpolate
之前的局部變量映射表來(lái)代替 keys
:
local function getLocals(level)
local i = 1
local locals = {}
while true do
local name, value = debug.getlocal(level, i)
if not name then
break
end
locals[name] = value
i = i + 1
print('locals: ', name, value)
end
return locals
end
function string.interpolate(fmt)
local locals = getLocals(3)
local ret =
string.gsub(
fmt,
'{%w+}',
function(c)
local key = string.match(c, "(%w+)")
local val = locals[key] or _G[key]
-- 轉(zhuǎn)化為字符串
val = tostring(val == nil and '' or val)
return val
end
)
return ret
end
這樣一來(lái)兽狭,就可以省略 keys
,使用起來(lái)也更靈活:
-- test
local who = "I"
local name = "DoooReyn"
local from = "China"
print(string.interpolate('Hi! {who} am {name}, {who} am from {from}'))
但是這樣存在一些問(wèn)題:
- 一是,如果局部變量很多箕慧,緩存的局部變量表就會(huì)很大服球,很浪費(fèi)內(nèi)存;如果改為每提取一個(gè)變量就去查詢一次颠焦,額外的操作又會(huì)很多斩熊;
- 二是,如果變量是全局的伐庭,
getlocal
是找不到的粉渠,于是就要增加去全局中查找的操作。
目前沒(méi)有想到很好的解決方法圾另,還是推薦使用第一種方式霸株,畢竟它目的足夠清楚,也不會(huì)有額外的損耗集乔。
?? 如果你喜歡這篇文章去件,請(qǐng)給我一個(gè)Star?吧!