0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Luaのテーブルを再帰的に展開してプリント

0
Last updated at Posted at 2026-07-10

多分こんなの既に無限にあるんだろうなと思いつつ、ネットで見付けた物を元にして自分的に丁度良い程度のを作った。

リンク

コード

Qiitaのシンタックスハイライトが記事公開時点では構文エラーっぽくなっているが、ちゃんと動くのでご安心を。

function tprint(tbl, indent, tprinted)
  indent = indent or 0
  tprinted = tprinted or { [tostring(tbl)] = true }
  local indentstr = string.rep("  ", indent)
  if not next(tbl) then
    print(indentstr .. "(empty)")
  else
    for k, v in pairs(tbl) do
      local vstr = tostring(v)
      local header = string.format("%s[%s] ", indentstr, k)
      if type(v) == "table" then
        if tprinted[vstr] then
          print(header .. vstr .. " (already printed)")
        else
          tprinted[vstr] = true
          print(header .. vstr)
          tprinted = tprint(v, indent + 1, tprinted)
        end
      else
        if type(v) == "string" then
          v = v:gsub("\\", "\\\\"):gsub('"', '\\"')
               :gsub("\n", "\\n"):gsub("\r", "\\r")
               :gsub("\t", "\\t"):gsub("\v", "\\v")
               :gsub("\a", "\\a"):gsub("\b", "\\b"):gsub("\f", "\\f")
          vstr = '"' .. v .. '"'
        end
        print(header .. vstr)
      end
    end
  end
  return tprinted
end

機能

  • テーブルを再帰的に展開してプリント
  • 値は tostring() してどんな型でも安全に
    • v が関数等の場合に header .. v なんてできない
  • 空のテーブルを明示
  • _G の様な自己参照的なテーブルにおける無限ループを防ぐため、プリント済みのテーブルは再展開しない
    • _G._G_G.package.loaded._G には _G が入っているし、_G.package.loaded.package には _G.package が入っているので、馬鹿正直な全展開は無限ループに陥る
  • 読みやすさやインデント構造保持のため、文字列をリテラル風に整形
    • "文字列" のようにダブルクォート
    • \" をエスケープ
    • 主要な制御文字(改行等)をエスケープシーケンスで表現
      • 特に改行がそのままだと、インデントの深さでテーブルの深さを表すという出力整形法則が崩れる

使用例

local tbl = { 42, true, a = "A", c = "C:\\Windows" }
tbl.lines = [[Lorem
ipsum
dolor]]
tbl.empty = {}
tbl.nested = { 100, 200, { 300 } }
tbl.square = function(v) return v * v end
tbl.self = tbl

tprint(tbl)
標準出力
[1] 42
[2] true
[self] table: 0x23779f00 (already printed)
[square] function: 0x2376a2d0
[empty] table: 0x2376a338
  (empty)
[nested] table: 0x23766678
  [1] 100
  [2] 200
  [3] table: 0x2376a298
    [1] 300
[lines] "Lorem\nipsum\ndolor"
[c] "C:\\Windows"
[a] "A"

キー順がまちまちなのは pairs() の仕様なのでご愛嬌。

応用: キー順を固定したい場合

順序を固定したければ、一旦キーだけテーブルに収集してソートしてからそれをループすれば良い。

ただし、数値と文字列のキーが混在すると attempt to compare string with number エラーが出るので、比較時には tostring() で正規化する。
また、数値っぽい文字列キーがあると結果を見て混乱するので、文字列キーも "文字列リテラル風" にする方が親切だろう。表示が少しクドくなるが。

function tprint(tbl, indent, tprinted)
  indent = indent or 0
  tprinted = tprinted or { [tostring(tbl)] = true }
  local indentstr = string.rep("  ", indent)
  if not next(tbl) then
    print(indentstr .. "(empty)")
  else
    local keys = {}
    for k, _ in pairs(tbl) do table.insert(keys, k) end
    table.sort(
      keys,
      function(a, b)
        local aType, bType = type(a), type(b)
        if aType == bType then return a < b
        else return aType == "number"
        end
      end
    )
    local function formatstr(v)
      if type(v) == "string" then
        v = v:gsub("\\", "\\\\"):gsub('"', '\\"')
             :gsub("\n", "\\n"):gsub("\r", "\\r")
             :gsub("\t", "\\t"):gsub("\v", "\\v")
             :gsub("\a", "\\a"):gsub("\b", "\\b"):gsub("\f", "\\f")
        return '"' .. v .. '"'
      else
        return tostring(v)
      end
    end
    for _, k in ipairs(keys) do
      local v = tbl[k]
      local vstr = formatstr(v)
      local header = string.format("%s[%s] ", indentstr, formatstr(k))
      if type(v) == "table" then
        if tprinted[vstr] then
          print(header .. vstr .. " (already printed)")
        else
          tprinted[vstr] = true
          print(header .. vstr)
          tprinted = tprint(v, indent + 1, tprinted)
        end
      else
        print(header .. vstr)
      end
    end
  end
  return tprinted
end

使用例
local tbl = { 42, true, a = "A", c = "C:\\Windows", ["01"] = 1 }
tbl.lines = [[Lorem
ipsum
dolor]]
tbl.empty = {}
tbl.nested = { 100, 200, { 300 } }
tbl.square = function(v) return v * v end
tbl.self = tbl

tprint(tbl)
使用例: 標準出力
[1] 42
[2] true
["01"] 1
["a"] "A"
["c"] "C:\\Windows"
["empty"] table: 0x2373aaa8
  (empty)
["lines"] "Lorem\nipsum\ndolor"
["nested"] table: 0x2f271dc0
  [1] 100
  [2] 200
  [3] table: 0x30ac8650
    [1] 300
["self"] table: 0x237648e0 (already printed)
["square"] function: 0x30a71438

おわり

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?