如何对 ConTeXt 中登记册中的某些项目进行分类并打印?

如何对 ConTeXt 中登记册中的某些项目进行分类并打印?

我在我的文档中创建了许多这样的寄存器,它可以让我存储词汇,\definevocabulary{word}然后使用并稍后调用列表\placeregister[vocabulary]

\defineregister[vocabulary][pagenumber=no, indicator=no, before=, n=1]
\def\definevocabulary{\vocabulary}
\starttext
    \definevocabulary{fish}
    \definevocabulary{bear}
    \placeregister[vocabulary]
\stoptext

当我调用列表时,它会打印所有单词。在某些情况下,我只想显示列表的子集。例如,有些单词被视为高优先级,我只需要打印这些单词。其他单词可能被标记为“针对 5 年级学生”或“针对 6 年级学生”,我可能只需要列出其中一组,或者列出“针对 5 年级学生和高优先级”的组合。

我能想到的唯一解决方案是创建许多不同的寄存器,并将单词添加到适合的寄存器中,但这似乎是一个过于复杂的解决方案:

\defineregister[allvocabulary]
\defineregister[all5thgradevocabulary]
\defineregister[all6thgradevocabulary]
\defineregister[allhighpriorityvocabulary]
\defineregister[all5thgradehighpriorityvocabulary]
\defineregister[all6thgradehighpriorityvocabulary]

ConTeXt 是否有办法标记进入登记册的物品,以便只列出符合特定标准(有时是多个标准)的物品?

答案1

为什么不简单地定义多个寄存器并在显示时合并它们。

\defineregister[easyvocabulary][pagenumber=no, indicator=no, before=, n=1]
\defineregister[hardvocabulary][pagenumber=no, indicator=no, before=, n=1]

\starttext
\easyvocabulary{fish}
\hardvocabulary{what}
\easyvocabulary{bear}
\hardvocabulary{aligator}
\subject{Both registers}
\placeregister[easyvocabulary,hardvocabulary]

\subject{Easy words}
\placeregister[easyvocabulary]

\subject{Hard words}
\placeregister[hardvocabulary]

\stoptext

这使

在此处输入图片描述

答案2

我使用标签进行了一些 hack。本质上,您定义的词汇表内容存储在 lua 中structures.registers.collected.vocabulary.entries。我不确定该表的哪些部分可以安全访问,因此我创建了一个外部表来跟踪标签。然后,当您想要放置特定标签时,我会备份主词汇表列表,对其进行过滤,放置它,然后恢复它。结果有点混乱,但希望可以避免 ConTeXt 内部的复杂化……也许有人可以纠正我这一点。

完整解决方案:

\defineregister[vocabulary][pagenumber=no, indicator=no, before=, n=1]

\startluacode
  userdata = userdata or {}
  userdata.tags = {}

  -- Table copy function from https://stackoverflow.com/questions/640642/how-do-you-copy-a-lua-table-by-value
  local function copy(obj, seen)
    if type(obj) ~= 'table' then return obj end
    if seen and seen[obj] then return seen[obj] end
    local s = seen or {}
    local res = setmetatable({}, getmetatable(obj))
    s[obj] = res
    for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end
    return res
  end

  -- Test for presence of tag
  local function isin(item, tags)
    for _, tag in ipairs(tags) do
      local inner = false
      for _, value in ipairs(userdata.tags[tag]) do
        if item == value then 
          inner = true
          break
        end
      end
      if not inner then
        return false
      end
    end
    return true
  end

  userdata.add_tags = function(item, s) 
    -- Split string
    local tags = lpeg.split(lpeg.patterns.spacer, s or "")
    for _,tag in pairs(tags) do
      userdata.tags[tag] = userdata.tags[tag] or {}
      table.insert(userdata.tags[tag], item)
    end
  end

  userdata.filter_items = function(s)
    local tags = lpeg.split(lpeg.patterns.spacer, s or "")

    -- Backup current vocabulary
    local vocabulary = structures.registers.collected.vocabulary.entries
    userdata.backup = copy(vocabulary)

    -- Filter only tags we want
    local n = #vocabulary
    -- Going backwards to not disrupt order
    for i = n, 1, -1 do
      if not isin(vocabulary[i].list[1][1], tags) then
        table.remove(vocabulary, i)
      end
    end
  end

  userdata.restore_items = function()
    structures.registers.collected.vocabulary.entries = copy(userdata.backup)
  end

\stopluacode

\define[2]\definevocabulary{%
  \vocabulary{#1}%
  \ctxlua{userdata.add_tags([==[#1]==], [==[#2]==])}%
}

\define[1]\placevocabulary{%
  \ctxlua{userdata.filter_items([==[#1]==])}%
  \placeregister[vocabulary] %
  \ctxlua{userdata.restore_items()}%
}

\starttext
    \definevocabulary{fish}{animal water}
    \definevocabulary{bear}{animal land}
    \definevocabulary{kelp}{plant water}
    \definevocabulary{apple}{plant land}

    Animals:
    \placevocabulary{animal}

    \blank[big]
    Plants:
    \placevocabulary{plant}

    \blank[big]
    Land plants:
    \placevocabulary{plant land}

\stoptext

相关内容