首页 > 解决方案 > 解决“Pandoc 过滤器”页面上的第一个练习

问题描述

https://pandoc.org/filters.html#exercises上的第一个问题要求将所有文本转换为大写,除非它是 URL 或链接标题的一部分。因此,我在https://pandoc.org/lua-filters.html#execution-order阅读了关于 lua 过滤器中“执行顺序”的讨论并想出了

text = require 'text'

links = {}

function Link(el)
  links[el.target] = el.content
  return el
end

function Str(el)
  el.text = text.upper(el.text)
  return el
end

function Inlines(elems)
  for i=1,#elems,1 do
    if elems[i].tag == 'Link' then
      elems[i].content = '<====' .. links[elems[i].target] .. '====>' -- just so that I can see it in the document.
      -- elems[i].content = pandoc.Str 'hello'
    end
  end
  return elems
end

--[[ -- Explicitly force order of filters -- from "Execution Order" list...
return {
  { Link = Link,
    Str = Str,
    Inlines = Inlines
  }
}
]]

认为这将解决我的问题。但不知何故,我无法让它发挥作用。我还尝试通过强制调用过滤器的顺序(在脚本末尾......注释)来明确安排表格,但它似乎不起作用。我究竟做错了什么?

标签: luamarkdownpandoc

解决方案


练习要求:

将所有常规文本以全部大写形式放在降价文档中(不要触摸 URL 或链接标题中的文本)。

这可以按照您上面描述的方式完成:

local text = require 'text'
function Str (s)
  s.text = text.upper(s.text)
  return s
end

这样就只剩下 URL 和链接标题了。


单独留下链接文本有点困难。Pandoc Lua 过滤器以深度优先后序遍历文档树,因此只有在处理完其内容后才会处理Link节点。我们可以使用一个简单的过滤器来验证和可视化这一点

function Inline (i)
  print(i.tag, pandoc.utils.stringify(i))
end

在类似的输入上运行上述内容Hello, [Free Encyclopedia](https://en.wikipedia.org)会产生

Str     Hello,
Space    
Str     Free
Space    
Str     Encyclopedia
Link    Free Encyclopedia

使用Inlines而不是Inline没有什么不同:嵌套元素在我们知道它们属于哪个元素之前就被处理了。这实际上意味着我们不能(轻松地)阻止转换影响特定的子树。

这很不幸(而且,作为 Lua 过滤器系统的作者,我想在未来改变一些东西)。然而,并不是所有的都丢失了。我们可以通过一个简单的技巧来解决这个问题:保存,然后恢复原始链接内容:

local text = require 'text'
local links = pandoc.List()

function to_allcaps (s)
  s.text = text.upper(s.text)
  return s
end

function save_link (l)
  links:insert(l)
end

function restore_link (l)
  return links:remove(1)
end

return {
  {Link = save_link},
  {Str = to_allcaps},
  {Link = restore_link},
}

在这里,我们遍历文档 3 次,如返回的过滤器列表中的三个单独的过滤器所示。首先,我们将所有链接收集到一个列表中;然后我们将所有内容全部大写;最后我们恢复原始链接,从而撤消链接标题中的所有大写修改。

紧凑型:

local text = require 'text'
local links = pandoc.List{}
return {
  {Link = function (l) links:insert(l) end},
  {Str = function (s) return pandoc.Str(text.upper(s.text)) end},
  {Link = function (_) return links:remove(1) end},
}

推荐阅读