Lua Printf

lua-users home
wiki

此頁面說明如何在 Lua 中部分模擬 C `printf` 的字串格式化函式。

在 Lua 中

使用 `io.write()`、`print()` 和 `string.format()` 可以在 Lua 中輕鬆撰寫格式化文字。`io.write` 類似於 `print`,只不過 `io.write` 在每個輸出的結尾都不會加上換行。C 函式 `printf()` 可以模擬成

> io.write(string.format("Hello from %s on %s\n",_VERSION,os.date()))
Hello from Lua 5.1 on Mon Jan  1 22:11:56 2007

或者,可以用函式將其包起來,如下所示

printf = function(s,...)
           return io.write(s:format(...))
         end -- function

然後用這種方式使用

printf("Hello from %s on %s\n",_VERSION,date())

在以上的範例中,格式化字串與 `printf()` 的可變引數清單傳遞至 `string.format()`。`write()` 列印結果的格式化字串。[*1]

值得注意的是,Lua 5.1 字串方法的語法如何強制將第一個引數分開處理。這是合理的,因為它的角色與其他角色大不相同。

請注意,Lua 的 `string.format` 函式不支援完整的 C 格式化規格 [1],因此此函式無法直接取代。如果你想要使用 C 格式化規格的全部功能,你可以在 C 程式碼中執行 `printf` 呼叫,然後從 Lua 中呼叫它。或者,你可以使用 C 字串函式,在 Lua 中完全模擬你需要的行為(較為費工)。

在 C 中

以下面的方式,可以將以上的範例寫成 C 程式碼。這同時也能透過將兩個標準程式庫函式封裝成 upvalue 來最佳化,而不是每次都查詢(儘管每次查詢的優點是可以更動態)。不過你可能還是只想使用 Lua 版本。

static int l_printf (lua_State *L) {
  lua_pushvalue(L, lua_upvalueindex(2));
  lua_insert(L, 1);
  lua_call(L, lua_gettop(L) - 1, 1);
  lua_pushvalue(L, lua_upvalueindex(1));
  lua_pushvalue(L, -2);
  lua_call(L, 1, 0);
  return 0;
}

int luaopen_printf (lua_State *L) {
  lua_getglobal(L, "io");
  lua_getglobal(L, "string");
  lua_pushliteral(L, "write");
  lua_gettable(L, -3);
  lua_pushliteral(L, "format");
  lua_gettable(L, -3);
  lua_pushcclosure(L, l_printf, 2);
  /* With 5.1, I'd probably just return 1 at this point */
  lua_setglobal(L, "printf");
  return 0;
}

一個 C 函式 `l_printf` 在 Lua 中註冊為 `printf`。當從 Lua 呼叫 `l_printf` 時,`format()` 會以指定引數呼叫,然後 `write()` 會以 `format` 的結果以及所傳回結果的數量為呼叫參數。


-- 感謝 lhf 提供的範例

註腳

[*1] Lua 4 的版本是

function printf(...)
  write(call(format,arg))
end

static int l_printf (lua_State *l)
{
    lua_getglobal(L,"format");
    lua_insert(L,1);
    lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
    lua_getglobal(L,"write");
    lua_insert(L,1);
    lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
    return lua_gettop(L);
}

lua_register(L,"printf",l_printf);


-- Sirmabus:2009 年 9 月 13 日 - 對以上 Lua 程式碼的改進方式是使用 `pcall()` 包裝器,來捕獲錯誤並指出有問題的 `printf()`。否則就難以確切知道錯誤從何而來。

function printf(...)
   local function wrapper(...) io.write(string.format(...)) end
   local status, result = pcall(wrapper, ...)
   if not status then error(result, 2) end
end

最近的變更 · 偏好設定
編輯 · 記錄
最後編輯時間為 2009 年 9 月 14 日 上午 1:13 GMT (diff)