我正在构建一种由两部分组成的词典:第一部分是单词,第二部分是词根。我想自动跟踪哪些单词与哪些词根相关。我已经掌握了这样做的信息:
% \entryword[ROOT]{LANGUAGE}{WORD}{DESCRIPTION}
% \entryword[serve]{english}{reserve}{This is a wonderful word.}
% \entryword{english}{thing}{There's no root for this one.}
\newcommand{\entryword}[4][]{
\ifthenelse{\isempty{#1}}
{}
{
% The optional argument, if not empty, represents the root.
% Now, I would like to annotate this word in the list of
% relatives of the specified root. It should be done here, I think.
}
\entryprompt{\foreignlanguage{#2}{#3}}
#4
\ifthenelse{\isempty{#1}}
{}
{
Root: \textit{-#1-}.
}
}
通过以类似数组的方式方便地存储每个根的亲属,我可以自动打印它们:
% \entryroot{serve}{This root comes from latin.}
\newcommand{\entryroot}[2]{
\entryprompt{\textit{-#1-}}
#2
% Here, how could I automate it?
Relatives: .
}
一位 MWE 表示:
\documentclass[b5paper,11pt]{report}
\usepackage[b5paper,margin=1.5cm]{geometry}
\usepackage{multicol}
\usepackage[main=english]{babel}
\usepackage[utf8]{inputenc}
\usepackage{xifthen}
\newcommand{\entryprompt}[1]{
{
\par\noindent
\textbf{\textsf{#1}}
}
}
\newcommand{\entryword}[4][]{
\ifthenelse{\isempty{#1}}
{}
{
% The optional argument, if not empty, represents the root.
% Now, I would like to annotate this word in the list of
% relatives of the specified root.
}
\entryprompt{\foreignlanguage{#2}{#3}}
#4
\ifthenelse{\isempty{#1}}
{}
{
Root: \textit{-#1-}.
}
}
\newcommand{\entryroot}[2]{
\entryprompt{\textit{-#1-}}
#2
% Here, how could I automate it?
Relatives: .
}
\begin{document}
\thispagestyle{empty}
\begin{center}
\Large
\textbf{Words}
\end{center}
\newpage
\begin{multicols}{2}
\entryword[serve]{english}{reserve}{This is a wonderful word.}
\entryword{english}{thing}{There's no root for this word.}
\end{multicols}
\newpage
\thispagestyle{empty}
\begin{center}
\Large
\textbf{Roots}
\end{center}
\newpage
\begin{multicols}{2}
\entryroot{load}{I don't know where this one comes from.}
\entryroot{serve}{This root comes from latin.}
\end{multicols}
\end{document}
理想情况下,亲属关系应存储在一种可以遍历的表中,以便以多种方式打印。我已经查看了该arrayjobx
包,但它似乎不能满足我的要求。特别是:
- 字符串不能作为索引。
- 它似乎没有提供一种在数组末尾添加元素的简单方法。
正如 egreg 所建议的,我添加了所需输出的示例:
- 字 -
保留 - 这是一个很棒的词。词根:服务。
事物——这个词没有词根。
-- 根 --
加载-我不知道这个是从哪里来的。
服务 - 这个词根来自拉丁语。相关词:保留。
答案1
您可以定义一个数组,在处理时加载与根相关的内容\entryword
。使用时\entryroot
,会打印该数组。
\documentclass{article}
\usepackage[english]{babel}
\usepackage{xparse}
\NewDocumentCommand{\entryprompt}{mm}{%
\par\noindent\textbf{\textsf{#1}} #2%
}
\ExplSyntaxOn
\NewDocumentCommand{\entryword}{ommm}
{
\entryprompt{\foreignlanguage{#2}{#3}}{#4}
\IfValueT{#1}
{% if a root is present, print it
\ Root:\nobreakspace#1
% then add the word as a relative to the root
\kalrish_addtoroot:nn { #3 } { #1 }
}
}
\NewDocumentCommand{\entryroot}{mm}
{
\par\noindent
#1\nobreakspace--\nobreakspace#2
% if the root has relatives, the corresponding sequence exists
\seq_if_exist:cT { g_kalrish_root_ \tl_to_str:n { #1 } _seq }
{
% start printing the relatives
\c_space_tl Relatives:~
% separated by a comma
\seq_use:cn { g_kalrish_root_ \tl_to_str:n { #1 } _seq } { ,~ }
}
}
\cs_new_protected:Npn \kalrish_addtoroot:nn #1 #2
{
% if a root appears for the first time, allocate a sequence
\seq_if_exist:cF { g_kalrish_root_ \tl_to_str:n { #2 } _seq }
{
\seq_new:c { g_kalrish_root_ \tl_to_str:n { #2 } _seq }
}
% add the current word as a relative
\seq_gput_right:cn { g_kalrish_root_ \tl_to_str:n { #2 } _seq } { #1 }
}
\ExplSyntaxOff
\begin{document}
\section{Words}
\entryword[serve]{english}{reserve}{This is a wonderful word.}
\entryword{english}{thing}{There's no root for this word.}
\entryword[serve]{english}{service}{This is also a word of tennis}
\section{Roots}
\entryroot{load}{I don't know where this one comes from.}
\entryroot{serve}{This root comes from latin.}
\end{document}
答案2
另一种不需要任何包的解决方案(因为只使用了 TeX 原语和基本宏):
\def\sxdef#1{\expandafter\xdef\csname#1\endcsname}
\def\entryword{\def\opt{}\futurelet\next\entrywordA}
\def\entrywordA{\ifx\next[\expandafter\entrywordB \else \expandafter\entrywordC \fi}
\def\entrywordB[#1]{\def\opt{#1}\entrywordC}
\def\entrywordC#1#2#3{{\bf#2} #3%
\ifx\opt\empty \else \space Root: \opt
\expandafter\ifx \csname r:\opt\endcsname \relax \sxdef{r:\opt}{#2}%
\else \sxdef{r:\opt}{\csname r:\opt\endcsname, #2}\fi
\fi}
\def\entryroot#1#2{#1 -- #2%
\expandafter \ifx \csname r:#1\endcsname \relax \else
\space Relatives: \csname r:#1\endcsname \fi
}
\entryword[serve]{english}{reserve}{This is a wonderful word.}
\entryword{english}{thing}{There's no root for this word.}
\entryword[serve]{english}{service}{This is also a word of tennis}
\entryroot{load}{I don't know where this one comes from.}
\entryroot{serve}{This root comes from latin.}
\end
答案3
这是一个适合进一步编辑的演示,骨架是用 LuaLaTeX 编写的。
我们将所有单词和词根存储在两个外部文件中,并在下次运行 TeX 时加载它们。关键行是\newcommand\entryword[4][]{\directlua{storeword([[#1]],[[#2]],[[#3]],[[#4]])}}
将所有 TeX 参数传递给 Lua,storeword
在本例中传入函数。我们甚至可以用 Lua 处理 TeX 文件(纯文本),而无需 TeXing。
还有很多可能的改进,我们可以补充:
- 页码:定义<->列表,双向(
\label
,,)。\ref
\pageref
- 交叉引用:两个方向的单词<->词根(有或没有测试条目的存在)。
- 对条目进行排序(例如在 Lua、MakeIndex、Xindy、Biber 等中)。现在,条目已散列,因此每次运行 TeX 后,我们可能会得到不同的条目顺序。自己尝试一下。:-)
我们运行lualatex
,我附上mal-root.tex
文件和结果预览。
% lualatex mal-root.tex
\documentclass[a4paper]{article}
\pagestyle{empty}
\usepackage{luacode}
\parindent=0pt
\begin{document}
\begin{luacode*}
malwords={}
malroots={}
-- Store a single word to a data table...
function storeword(root,lang,word,text)
-- print(root,lang,word,text)
-- split root(s) to a table
roots={}
for singleroot in string.gmatch(root, "([^,]+)") do
table.insert(roots, singleroot)
end
malwords[word]={ roots, lang, text }
end -- function storeme
-- Store a single root to a data table...
function storeroot(root,text)
-- print(root,text)
malroots[root]={ text }
end -- function storeroot
-- Print both lists (words, roots)...
function printall(orderfile)
-- load stored files if they exist
for _,malf in pairs({"dumpwords.lua","dumproots.lua"}) do
f=io.open(malf,"r")
if f then f:close(); dofile(malf); end -- print(malf);
end -- for, files
-- Typeset the first list...
if orderfile==1 and malwordsfull then -- words
tex.print("\\section{List of Words}")
for theword,term in pairs(malwordsfull) do
mals="\\textbf{"..theword.."} -- "..term[3]
if #term[1]>0 then
mals=mals.." Root"
if #term[1]>1 then mals=mals.."s" end
mals=mals..": "
for elemi,elem in pairs(term[1]) do
mals=mals..elem
if elemi<#term[1] then mals=mals..", " end
end -- for
end -- if #>0
mals=mals.."\\par"
tex.print(mals)
end
end -- words
-- Typeset the other list (to add cross references?)
if orderfile==2 and malrootsfull then -- roots
tex.print("\\section{List of Roots}")
-- Check all roots...
for theword,term in pairs(malrootsfull) do
mals="\\textbf{"..theword.."} -- "..term[1]
toadd=""; counter=0
-- Check all words...
for elem,oword in pairs(malwordsfull) do
-- Check all roots in words...
for oroota,oroot in pairs(oword[1]) do
if oroot==theword then counter=counter+1; toadd=toadd..elem..", " end
end -- for rootsfull
end -- if orderfile
if counter>0 then
mals=mals.." Relative"
if counter>1 then mals=mals.."s" end
mals=mals..": \\textit{"..string.sub(toadd,1,-3).."}"
end -- if
mals=mals.."\\par"
tex.print(mals)
end -- for
end -- if
end -- function printwords()
-- http://stackoverflow.com/questions/9168058/lua-beginner-table-dump-to-console
function dumper(o)
if type(o) == 'table' then
local s = '\n{'
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dumper(v) .. ', '
end
return s..'}\n'
else
return '"'..tostring(o)..'"'
end
end
-- Save data to a single file...
function savedata(file, data, name)
saveme=io.open(file, "w")
mojkovo=name.." = "..dumper(data, name)
saveme:write(mojkovo)
saveme:close()
end
-- Save both data tables...
function saveall()
savedata("dumpwords.lua", malwords, "malwordsfull")
savedata("dumproots.lua", malroots, "malrootsfull")
end
\end{luacode*}
% Let's call Lua...
\newcommand\entryword[4][]{\directlua{storeword([[#1]],[[#2]],[[#3]],[[#4]])}}
\newcommand\entryroot[2]{\directlua{storeroot([[#1]],[[#2]])}}
\newcommand\printwords{\directlua{printall(1)}}
\newcommand\printroots{\directlua{printall(2)}}
\newcommand\savedata{\directlua{saveall()}}
% Call Lua to work (data from the previous TeX run)...
\printwords
\printroots
% Let's test if it works (some words) and ...
\entryword[sleep1,sleep2]{english}{sleeping}{A word with more roots.}
\entryword[serve]{english}{reserve}{This is a wonderful word.}
\entryword{english}{thing}{There's no root for this word.}
\entryword[serve]{english}{service}{This is also a word of tennis.}
% ... and (some roots)
\entryroot{load}{I don't know where this one comes from.}
\entryroot{serve}{This root comes from latin.}
% Save all data to two external files for next TeX run...
\savedata
\end{document}