在lua中使用字符串内的变量

S. *_*enk 13 lua

在 javascript 中我们可以执行以下操作:

var someString = `some ${myVar} string`
Run Code Online (Sandbox Code Playgroud)

我有以下lua代码,myVar是一个需要放在方括号中的数字:

splash:evaljs('document.querySelectorAll("a[title*=further]")[myVar]')
Run Code Online (Sandbox Code Playgroud)

Gre*_*een 15

符合您描述的功能是string.format

splash:evaljs(string.format('document.querySelectorAll("a[title*=further]")[%s]', myVar))
Run Code Online (Sandbox Code Playgroud)

它不像 那样冗长${}。它更像是一个很好的旧的(并且令人讨厌的)sprintf


ton*_*mtr 9

我编写了 Python 字符串的模拟f'',它是一组可以隐藏在require文件中的函数。所以,如果您喜欢 Python 的f''字符串,这可能就是您正在寻找的。

(如果有人发现错误,请告知。)

与其他解决方案相比,它相当大,但如果您将大部分内容隐藏在库中,那么它的使用会更加紧凑和可读,IMO。

使用此库,您可以执行以下操作,例如:

require 'f_strings'
a = 12345
print(f'Number: {a}, formatted with two decimals: {a::%.2f}')
-- Number: 12345, formatted with two decimals: 12345.00
Run Code Online (Sandbox Code Playgroud)

请注意 Lua 格式化代码的使用string.format,以及格式说明符使用双冒号(而不是 Python 的单冒号),因为 Lua 对方法使用冒号。

我只从一个更大的库中提取了相关函数。尽管对于这个特定的用例可能可以进行一些优化,但我保留它们不变,因为它们是通用目的,并且也可能用于其他目的。

这是所需的库(放置在 Lua 库文件夹中的某个位置):

-- f_strings.lua ---
unpack = table.unpack or unpack

--------------------------------------------------------------------------------
-- Escape special pattern characters in string to be treated as simple characters
--------------------------------------------------------------------------------

local
function escape_magic(s)
  local MAGIC_CHARS_SET = '[()%%.[^$%]*+%-?]'
  if s == nil then return end
  return (s:gsub(MAGIC_CHARS_SET,'%%%1'))
end

--------------------------------------------------------------------------------
-- Returns iterator to split string on given delimiter (multi-space by default)
--------------------------------------------------------------------------------

function string:gsplit(delimiter)
  if delimiter == nil then return self:gmatch '%S+' end --default delimiter is any number of spaces
  if delimiter == '' then return self:gmatch '.' end
  if type(delimiter) == 'number' then   --break string in equal-size chunks
    local index = 1
    local ans
    return function()
             ans = self:sub(index,index+delimiter-1)
             if ans ~= '' then
               index = index + delimiter
               return ans
             end
           end
  end
  if self:sub(-#delimiter) ~= delimiter then self = self .. delimiter end
  return self:gmatch('(.-)'..escape_magic(delimiter))
end

--------------------------------------------------------------------------------
-- Split a string on the given delimiter (comma by default)
--------------------------------------------------------------------------------

function string:split(delimiter,tabled)
  tabled = tabled or false              --default is unpacked
  local ans = {}
  for item in self:gsplit(delimiter) do
    ans[#ans+1] = item
  end
  if tabled then return ans end
  return unpack(ans)
end

--------------------------------------------------------------------------------

function copy(t)              --returns a simple (shallow) copy of the table
  if type(t) == 'table' then
    local ans = {}
    for k,v in next,t do ans[ k ] = v end
    return ans
  end
  return t
end

--------------------------------------------------------------------------------

function eval(expr,vars)
  --evaluate a string expression with optional variables
  if expr == nil then return end
  vars = vars or {}
  assert(type(expr) == 'string','String expected as 1st arg')
  assert(type(vars) == 'table','Variable table expected as 2nd arg')
  local env = {abs=math.abs,acos=math.acos,asin=math.asin,atan=math.atan,
               atan2=math.atan2,ceil=math.ceil,cos=math.cos,cosh=math.cosh,
               deg=math.deg,exp=math.exp,floor=math.floor,fmod=math.fmod,
               frexp=math.frexp,huge=math.huge,ldexp=math.ldexp,log=math.log,
               max=math.max,min=math.min,modf=math.modf,pi=math.pi,pow=math.pow,
               rad=math.rad,random=math.random,randomseed=math.randomseed,
               sin=math.sin,sinh=math.sinh,sqrt=math.sqrt,tan=math.tan,
               tanh=math.tanh}
  for name,value in pairs(vars) do env[name] = value end
  local a,b = pcall(load('return '..expr,nil,'t',env))
  if a == false then return nil,b else return b end
end

--------------------------------------------------------------------------------
-- f'' formatted strings like those introduced in Python v3.6
-- However, you must use Lua style format modifiers as with string.format()
--------------------------------------------------------------------------------

function f(s)
  local env = copy(_ENV)                --start with all globals
  local i,k,v,fmt = 0
  repeat
    i = i + 1
    k,v = debug.getlocal(2,i)           --two levels up (1 level is this repeat block)
    if k ~= nil then env[k] = v end
  until k == nil
  local
  function go(s)
    local fmt
    s,fmt = s:sub(2,-2):split('::')
    if s:match '%b{}' then s = (s:gsub('%b{}',go)) end
    s = eval(s,env)
    if fmt ~= nil then
      if fmt:match '%b{}' then fmt = eval(fmt:sub(2,-2),env) end
      s = fmt:format(s)
    end
    return s
  end
  return (s:gsub('%b{}',go))
end
Run Code Online (Sandbox Code Playgroud)