几乎所有处理练习的软件包都允许我们向每个练习附加/检索元数据。
处理练习时可能需要的一些事项包括:
- 根据元数据过滤练习。
- 从外部文件中选择随机练习。
- 有与每个练习相关的动态数据。
我所说的“动态数据”是指可以随时间变化的数据。例如,tused
用于存储过去文档中使用某项练习的次数的键。
据我所知,这方面尚未涉及。
现在,让我更具体地说:
需要解决的问题
假设我想使用exsheets
包来处理我的考试题目。所以我做了类似的事情\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
,其中lsused
/lyused
上学期/年份的题目被使用过,并且tused
如上所述。
我可以按主题随机选择问题(通过将它们放在单独的外部文件中)。因此,我为每个主题都有一个文件,并且每个文件中的问题如下
\begin{question}[ID=L1]
\SetQuestionProperties{difficulty=hard,topic=logic,lsused=1,lyused=2011,tused=3}
Proof that this is not our first very hard question.
\end{question}
我需要查看问题的 ID,以便决定保留哪些问题、丢弃哪些问题。我们将其称为“选择阶段“。假设我的考试必须有 9 个问题,所以我会这样做:
\documentclass{article}
\usepackage{exsheets}
\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
\DebugExSheets{true}
\begin{document}
\includequestions[random=3,difficulty=easy]{logic}
\includequestions[random=3,difficulty=medium]{arithmetic}
\includequestions[random=3,difficulty=hard]{geometry}
\end{document}
请注意,如果我多次编译此文件,每次我可能会得到一组不同的问题。
第一个问题就出现在这里:我不确定我们是否可以根据用户定义的属性过滤问题。通过 ID 避免问题会很有用,例如一些:
\includequestions[random=3,difficulty=easy,noIDs={L5,L6}]{logic}
而且,即使我们能够这样做,最好还是有办法进入“初步阶段“它允许我们将上次编译中获得的练习(例如,通过将其 ID 和所属的主题/文件存储在外部文件中)保存在“选择阶段“并直接改变我们不想要的问题。
假设解决所有这些问题的包名为upackage
。并且它提供了方法来说明我们处于哪个阶段。假设此后出现的所有未知命令都由该包提供。因此,在第一阶段,我会执行类似以下操作:
\documentclass{article}
\usepackage{exsheets}
\usepackage{upackage}
\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
\DebugExSheets{true}
\begin{document}
\setstage{selection}
\includequestions[random=3,difficulty=easy]{logic}
\includequestions[random=3,difficulty=medium]{arithmetic}
\includequestions[random=3,difficulty=hard]{geometry}
\end{document}
假设在编译完这个之后,我喜欢除第二道几何题之外的所有题目。所以我会这样做:
\documentclass{article}
\usepackage{exsheets}
\usepackage{upackage}
\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
\DebugExSheets{true}
\begin{document}
\setstage{preliminary}
\changequestion{number=2,topic=geometry}
\end{document}
我期望的是,我之前遇到的问题与此相同,但第二道几何题有所不同。如果仍然不喜欢,我只需重新编译。这有点复杂,因为它必须跟踪不需要的问题列表。在这里我假设文件名和主题是相同的。
一旦我决定这 9 个问题没问题,我就会这样做:
\documentclass{article}
\usepackage{exsheets}
\usepackage{upackage}
\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
\begin{document}
\setstage{final}
\end{document}
这次我得到了问题,但没有显示它们的 ID。另一个问题就在这里。假设包允许我们设置\currentsemester
和\currentyear
(默认情况下必须是\year
)。我希望当文档被标记为时final
,属性lsused
会lyused
在相应的问题中更新,并且tused
必须在 中增加一。这对于设置很有用,\tolerance
例如,如果我设置\tolerance{2}
并且我在 2013 年的第一学期,这将避免包括过去一年使用的问题。
因此,建立考试的流程简而言之应该是:
选择:
\documentclass{article}
\usepackage{exsheets}
\usepackage{upackage}
\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
\DebugExSheets{true}
\currentsemester{1}
\currentyear{2013}
\tolerance{2}
\begin{document}
\setstage{selection}
\includequestions[random=3,difficulty=easy]{logic}
\includequestions[random=3,difficulty=medium]{arithmetic}
\includequestions[random=3,difficulty=hard]{geometry}
\end{document}
初步的:
\documentclass{article}
\usepackage{exsheets}
\usepackage{upackage}
\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
\DebugExSheets{true}
\currentsemester{1}
\currentyear{2013}
\tolerance{2}
\begin{document}
\setstage{preliminary}
\changequestion{number=2,topic=geometry}
\end{document}
直到第二道几何题可以接受。
最终的:
\documentclass{article}
\usepackage{exsheets}
\usepackage{upackage}
\DeclareQuestionProperty{difficulty,topic,lsused,lyused,tused}
\DebugExSheets{true}
\currentsemester{1}
\currentyear{2013}
\tolerance{2}
\begin{document}
\setstage{final}
\end{document}
问题
我的问题是,使用 TeX/LaTeX 实现这样的事情可行吗?还有其他方法吗?如何解决这些问题?
答案1
再次抱歉,我不再挖掘这个非常古老的话题。
如果我可以补充一下前面的答案,至少有两个程序是专门为此设计的(开源,带有 GUI)。因此,这回答了“其他方法”部分,而不是“纯 LaTeX”部分。
- 特克萨姆特(免责声明:我是作者)
基本上,它会递归地遍历一个特定的文件夹来查找您的 .tex 文件及其中的所有练习。然后,您可以单击包含练习的文件,它会即时编译它以向您显示练习:将您想要的练习添加到最终文档中,然后将其导出(导出为 tex 或 pdf)。
- TeXoMaker(免责声明:我不是作者;))
这个的工作原理几乎与前一个相同,只是您必须先创建一个练习数据库,然后才能使用它。
这两种软件都具有“搜索”功能,因此您可以根据需要使用元数据,例如,仅显示困难的练习。
至少在 TeXamator 中你可以添加随机选择的练习(也许在 TeXoMaker 中也可以,但我不能肯定)。
希望这可以帮助 !
答案2
在 LaTeX 中实现这样的事情是非常合理的,但是如果你熟悉 Unix 系统,我宁愿建议依靠 shell 脚本和 makefile 来生成练习表。
走 TeX 之路
我(几乎)是从汇编语言开始学习计算机科学的,虽然这听起来可能令人惊讶,但我发现这种经验在编写 TeX 程序时非常有用 —— 如果你还记得 Knuth 对汇编语言的倾向,这听起来可能一点也不奇怪。
通过使用数据结构,您可以在 TeX 中设计任意复杂的宏集。借助宏读取和写入寄存器,使用受控扩展,可以最轻松地处理数据结构:edef,
xdef,
expandafter,
futurelet
令牌寄存器是交易工具。
如果你不熟悉这些技术,我建议你看看电子书当然,还有大卫·萨洛蒙的高级电子书强调使用更先进的技术。我为普通的 TeX 编写了一个宏包,该getoptk
包允许定义宏,使用奇特的(IEà la hbox
) 参数。该示例足够小,以便您可以快速掌握它,并展示了如何对 TeX 输入进行一些简单的词汇分析。
除了使用前面提到的受控扩展工具包之外,我建议避免定义错误谓词,即文本扩展包含 或iftrue
的测试宏iffalse
。这会使复杂条件的构造变得复杂。相反,您应该将测试逻辑和分支逻辑分开——在包ifgetoptbracket
中查找getoptk
。
此外,我发现将宏逻辑分成小块很有用,例如查看getoptk
宏的定义,它有许多标记的代码块geoptk@A
等等,一些后缀具有或多或少标准化的含义(对我来说)例如@L
循环和@E
退出或结束。
一旦您熟悉了这些技术,您就可以像在任何其他计算机语言中一样定义和使用抽象数据类型并描述复杂的算法。
您可能还对该包感兴趣graphicx
,它可以进行某种文件处理。(它在 EPS 文件中查找 bbox。)
CTAN 上的 getoptk 包: http://www.ctan.org/tex-archive/macros/plain/contrib/getoptk
TuGboat 的问题,其中描述了该软件包: http://tug.org/TUGboat/tb32-2
走 UNIX 之路
原生 TeX 解决方案具有可移植性的优势,但维护起来却比较麻烦。由于您要解决的问题可能没有明确说明(练习中有一些随机参数不是很好吗?等等),因此您可能希望扩展其功能。
如果您在 UNIX 系统上工作,并且熟悉 makefile、shell 编程和其他一些实用程序(主要是sed
和awk
)或编程语言,那么您可能希望设计自己的工作流程来编写 TeX 文件或include
主文档中的一部分。
顺便说一句,这种技术大大简化了复杂表格的生成。
我编写了几个称为 BSD Make Pallàs Scripts 的宏,它们使操作变得非常容易。
我的制作宏的文档: http://home.gna.org/bsdmakepscripts/tex.html
其他解决方案
如果您同意使用perltex
或luatex
或任何类似的东西,您也可以尝试它们,但我没有使用这些工具的经验。