🔗 String interpolation in Lua
Lua is known for having a very lean standard library, and for providing mechanisms to do things instead of a ton of features.
String interpolation isn’t available out of the box, but doing it in Lua isn’t a new trick. In fact, the manual includes it as an example of string.gsub:
local t = {name="lua", version="5.3"}
x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
--> x="lua-5.3.tar.gz"
This applies to members of a table only, though. Python is introducing a general string-interpolation syntax:
a = "Hello"
b = "World"
f"{a} {b}"
f"{a + ' ' + b}"
Given that Lua supports the f"str" syntax for functions with a single string argument, I thought it would be nice to put its Lua-provides-the-mechanisms ethos to test by trying to write my own Python-like f-string formatter.
And here it is, in all its 28-line glory (and I went for readability, and not to write it as short as possible):
function f(str)
local outer_env = _ENV
return (str:gsub("%b{}", function(block)
local code = block:match("{(.*)}")
local exp_env = {}
setmetatable(exp_env, { __index = function(_, k)
local stack_level = 5
while debug.getinfo(stack_level, "") ~= nil do
local i = 1
repeat
local name, value = debug.getlocal(stack_level, i)
if name == k then
return value
end
i = i + 1
until name == nil
stack_level = stack_level + 1
end
return rawget(outer_env, k)
end })
local fn, err = load("return "..code, "expression `"..code.."`", "t", exp_env)
if fn then
return tostring(fn())
else
error(err, 0)
end
end))
end
It works just like the Python example:
a = "Hello"
b = "World"
print(f"{a} {b}")
Unlike the one-liner from the Lua manual, it also works with local variables:
local c = "Hello"
local d = "World"
print(f"Also works with locals: {c} {d}")
do
local h = "Hello"
do
local w = "World"
print(f"Of any scope level: {h} {w}")
end
end
Some more demos:
print(f"Allows arbitrary expressions: one plus one is {1 + 1}")
local t = { foo = "bar" }
print(f"And values: t.foo is {t.foo}; print function is {_G.print}")
local ok, err = pcall(function()
print(f"This fails: { 1 + } ")
end)
print("Errors display nicely: ", err)
If there’s interest, I can make this a module in LuaRocks (probably calling it .F rather than f)
Update! This is now available in LuaRocks as a module! Install it with:
luarocks install f-strings
More info at the f-strings GitHub page. Enjoy!
Follow
🐘 Mastodon ▪ RSS (English), RSS (português), RSS (todos / all)
Last 10 entries
- Aniversário do Hisham 2025
- The aesthetics of color palettes
- Western civilization
- Why I no longer say "conservative" when I mean "cautious"
- Sorting "git branch" with most recent branches last
- Frustrating Software
- What every programmer should know about what every programmer should know
- A degradação da web em tempos de IA não é acidental
- There are two very different things called "package managers"
- Last day at Kong