使用lua过滤器迭代表行的问题

问题描述 投票:3回答:2

我正在尝试为pandoc写一个简单的lua过滤器,以便对ReST表中的元素进行一些宏扩展。

filter.lua

function tablelength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

function Table(table)

    elems=pandoc.Table(table)["rows"]

    print(tablelength(table))
    for v in pairs(elems) do
        print(v) -- Prints nothings
    end
    return table
end

test.rst

======= =========
A       B 
======= =========
{{x}}   {{y}}
======= =========

现在,如果我运行pandoc.exe -s --lua-filter filter.lua test.rst -t rst,程序会说elems中有5个元素,但是只跳过了for循环,我真的不知道我在做什么错。

我对Lua还是很陌生,也知道pandoc非常小。如何迭代元素中的元素?

lua python-sphinx pandoc restructuredtext
2个回答
2
投票

Pandoc lua过滤器提供了方便的walk_block帮助器,该帮助器递归地遍历文档树并将一个函数应用于与该键匹配的元素。

[在下面的示例中,我们给walk_block一个lua表(其他语言是映射或dict),它只有一个键(键Str),并且该表的值是要应用的函数。该功能检查大括号,剥去大括号并添加foo

function Table(table)
  return pandoc.walk_block(table, {
    Str = function(el)
      if el.text:sub(1,2) == '{{' then
        txt = 'foo' .. el.text:sub(3, -3)
      else
        txt = el.text
      end
      return pandoc.Str(txt)
    end
  })
end

0
投票

您的代码中有几个误区。首先,您需要记住lua中的所有内容都是一个表(实现为关联数组或字典),而数组只是表的一种特殊情况,其中键是整数。为避免混淆,在本答案的其余部分中,当我引用pandoc文档元素时,将使用Table;而在引用lua数据结构时,将使用table。]

您的tablelength函数仅计算代表表的pandoc表中的元素数。如果您查看https://www.pandoc.org/lua-filters.html#type-ref-Block,您将看到一个表格具有5个属性-标题,对齐,宽度,标题和行。因此,此函数的返回值为5。如果在表长度内的循环中打印出值,则将对此进行确认。如果要计算行数,则需要将行数组传递给函数,而不是表。

第二个问题是您正在创建一个新表,而不是使用pandoc传递的表。不用elems=pandoc.Table(table)["rows"]而是使用等效的elems=table["rows"]elems=table.rows。函数pandoc.Table()用于创建新元素。

此外,要遍历数组形式的表中的元素,您可以使用ipairs函数-它将返回数字索引值,如此处What is the difference of pairs() vs. ipairs() in Lua?所述。

正如预期的那样,行表是一个行数组,其中每一行又是一个元素数组。因此,要访问表的元素,您将需要有两个循环。

最后是pandoc对象模型的问题。因为表可以包含其他内容(图像,链接,粗体文本等),所以最终单元格值实际上是一个块列表。现在,根据您要对表执行的操作,可以用不同的方式来处理它。您可以使用mb21所引用的walk_block函数,但仅在单个单元格中循环遍历这些块。如果您的表仅包含(未格式化的)文本,则可以使用stringify函数来简化操作,该函数将块列表折叠为单个字符串。

将所有这些放在一起会得到下面的代码修改版本。

local stringify=pandoc.utils.stringify

-- This function is no longer needed
function tablelength(T)
  local count = 0
  for e in pairs(T) do 
    count = count + 1 
    print(e) -- this shows the key not the value
  end
  return count
end

function Table(table)

    rows=table["rows"]

    print("TableLength="..#rows)
    for rownum,row in ipairs(rows) do
        for colnum, elem in ipairs(row) do
            print(stringify(elem)) -- Prints cell text
        end
    end
    return table
end

关于您的后续问题,如果要修改内容,则只需要替换单元格值,同时尊重pandoc的对象模型即可。您可以使用pandoc模块中的构造函数来构造pandoc使用的各种类型(例如上述的pandoc.Table)。最简单的表格单元将是具有单个Plain块的数组,而该Plain块又包含单个Str元素(块通常包含Inline元素列表)。

以下代码显示了如何使用现有内容或行/列号来修改表。请注意,我将Table函数的参数从table更改为tableElem,因为table是lua中常用的类型,并且对其进行重写会导致难以跟踪的错误。

local stringify=pandoc.utils.stringify

function makeCell(s)
    return {pandoc.Plain({pandoc.Str(s)})}
end

function Table(tableElem)

    rows=tableElem["rows"]
    for rownum,row in ipairs(rows) do
        for colnum, elem in ipairs(row) do
            local elemText=stringify(elem)
            if elemText=="{{x}}" then
                row[colnum]=makeCell(elemText:gsub("x","newVal"))
            end
            if rownum==1 and colnum==2 then
                row[colnum]=makeCell("Single cell")
            end
        end
    end
    local newRow={ makeCell("New A"), makeCell("New B")}
    table.insert(rows,newRow)
    return tableElem
end
© www.soinside.com 2019 - 2024. All rights reserved.