文字範本

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) 說明了如何以組態檔中的資料結構值來填寫範本檔的良好技巧。

如果您唯一要做的只是將字串中的變數取代為表格中的值,請參閱 StringInterpolation

以下這個模組 `Expand.lua` [5] 使用 Bentley's 巨集擴充演算法,以及範本字串中變數參考的 GNU make 語法。它還有一些從 Mark J. Dominus 的 `Text::Template.pm` 和 Sriram Srinivasan 在 O'Reilly 的《進階 Perl 程式設計》第 17 章中範本驅動的程式碼產生器 `Jeeves` 獲得的改良。

目標是有一個稱為 `expand` 的函式,這個函式會掃描範本字串的變數參考,並遞迴地取代它們,使用在列出的某個表格或函式中找到的值。

範本語法非常簡單。對表格成員和變數的參考表示為 `$ {varname` } 或 `$(varname)`,或如果是單字元變數名稱,則表示為 `$x`。

也可以在 `$ {expr` } 或 `$(expr)` 中包裹回傳字串的簡單 Lua 運算式。

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 (比較結果)