文本模板

lua-users home
wiki

对于新的 Lua 程序员来说,一个很好的练习是使用 Lua 实现 Jon Bentley 的简单宏处理器 [4]。您可以在 O'Reilly 的 sed & awk 书籍第 13 章的末尾找到它 [1],或者在网上找到它 [2] [3]

宏处理器的缺点之一是它们没有数据结构。在 Lua 的旧版本(lua-4.0.1/test/examples/www/db.lua)中提供的一个示例展示了一种很好的技术,用于使用配置文件中的数据结构填充模板文件。

如果您只想用来自表的数值替换字符串中的变量,请参阅 字符串插值

以下模块,Expand.lua [5],使用 Bentley 的宏扩展算法,以及 GNU make 语法在模板字符串中引用变量。它还从 Mark J. Dominus 的 Text::Template.pm 和 Sriram Srinivasan 的模板驱动代码生成器 Jeeves(在 O'Reilly 的 高级 Perl 编程 第 17 章中)中获取了一些增强功能。

目标是拥有一个名为 expand 的函数,该函数扫描模板字符串以查找变量引用,并递归地将它们替换为在列出的表或函数中找到的数值。

模板语法非常简单。对表成员和变量的引用表示为 ${varname} 或 $(varname),或者如果它是一个字符的变量名,则表示为 $x

返回字符串的简单 Lua 表达式也可以用 ${ expr } 或 $( expr ) 包裹。

Lua 语句可以用以下之一包裹

Lua 代码可以设置一个名为 OUT 的变量,该变量将替换模板字符串中的代码。

Lua 表达式和语句由 loadstring 使用函数环境设置为第一个表来计算。

以下示例展示了如何使用 expand。请注意,Expand.lua 仅适用于 Lua 5.0。

expand = require'Expand'

template = [[
you can access variables: $v
or environment variables: ${HOME}

you can call functions: ${table.concat(list, ', ')}
this list has ${list.n} elements
   ${string.rep('=', list.n)}
   ${table.concat(list)}
   ${string.rep('=', list.n)}

or evaluate code inline
${for i=1,list.n do
    OUT = table.concat{ OUT, ' list[', i, '] = ', list[i], '\n'}
  end}
you can access global variables:
This example is from ${mjd} at $(mjdweb)

The Lord High Chamberlain has gotten ${L.n}
things for me this year.
${do diff = L.n - 5
    more = 'more'
    if diff == 0 then
      diff = 'no'
    elseif diff < 0 then
      diff = -diff
      more = 'fewer'
    end
  end}
That is $(diff) $(more) than he gave me last year.

values can have other variables: $(ref)
]]

mjd = "Mark J. Dominus"
mjdweb = 'http://perl.plover.com/'
L = { 'A', 'B', 'C', 'D', n=4}
local x = {
  v = 'this is v',
  list = L,
  ref = "$(mjd) made Text::Template.pm"
}
-- fill in the template with values in table x
io.write(expand(template, x, _G, os.getenv))
变量首先通过搜索本地表 x、然后搜索全局环境、最后通过调用 os.getenv 函数来找到。

以下是上面示例生成的输出

you can access variables: this is v
or environment variables: /home/pshook

you can call functions: A, B, C, D
this list has 4 elements
   ====
   ABCD
   ====

or evaluate code inline
 list[1] = A
 list[2] = B
 list[3] = C
 list[4] = D

you can access global variables:
This example is from Mark J. Dominus at http://perl.plover.com/

The Lord High Chamberlain has gotten 4
things for me this year.

That is 1 fewer than he gave me last year.

values can have other variables: Mark J. Dominus made Text::Template.pm
如果您想有条件地扩展模板字符串的某些部分,那么可以使用 $(when varname ...) 语法。如果 varname 不是 false,那么包含的字符串将进行宏扩展。如果 varname 是一个表,那么它将是包含的字符串进行宏扩展时搜索的第一个表。

代码生成的一个有用功能是 $(foreach tabname ...) 语法。如果 tabname 是一个包含表列表的表,那么对于 tabname 中的每个表,将对包含的字符串执行宏扩展,并将结果连接在一起。

expand = require'Expand'

fun_temp = [[
==============================================================================
$(foreach funcs

  ${type} x = ${name}( ${table.concat(args, ', ')} ) {
    $(code)
$(when stuff
    x = $x;
    y = $y;
)    reutrn $(exit);
  }
)
==============================================================================
]]

fun_list = {
  exit = 1;
  stuff = false;

  funcs = {
    { type = 'int';
      name = 'bill';
      args = { 'a', 'b', 'c' };
      code = 'something';
      stuff = { x=99, y=34 };
    };
    { type = 'char *';
      name = 'bert';
      args = { 'one', 'two', 'three' };
      code = 'something else';
      exit = 2
    };
  };
}

io.write(expand(fun_temp, fun_list, _G))
输出是
==============================================================================

  int x = bill( a, b, c ) {
    something
    x = 99;
    y = 34;
    reutrn 1;
  }

  char * x = bert( one, two, three ) {
    something else
    reutrn 2;
  }

==============================================================================

此页面的第一个版本是 OldTextTemplate

另请参阅


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2007 年 5 月 28 日下午 8:41 GMT (差异)