这在某种程度上是对上一个问题的扩展:用于在逗号分隔的列表中应用自定义命令的宏
我正在用 LaTex 创建花园日志。我有一个 .csv 植物数据库文件(数据库-1.csv) 我使用数据工具包中的条件为花园的每个区域创建子集表,效果非常好。
我想在我的每个表中索引从数据库中提取的植物。我目前正在使用 makeidx 包。这样,我的最终索引将包括提及特定植物的位置,即使该提及出现在表中而不是直接出现在文本中。
我怎样才能使我的应用宏对我的数据工具条件 (\theback) 的结果起作用?
这是我的 MWE:
\documentclass[12pt]{book}
\usepackage{datatool}
\usepackage{colortbl}
%necessary to color a table
\definecolor{lightmauve}{rgb}{0.86, 0.82, 1.0}
\usepackage{makeidx} % Required to make an index
\makeindex % Tells LaTeX to create the files required for indexing
% This command is for applying a single command to a comma-separated list of tokens, and listing the results separated by ", " (I removed the ``,'').
\makeatletter
\newcommand{\apply}[3][]{
% #1: optional separator to print between applications; default=[, ]
% #2: command to apply;
% #3: list to apply command to
\def\itemsep{\def\itemsep{#1}} % first call to \itemsep prints nothing; later calls print #1
\def\zz{\itemsep#2}%
\@for \listelement:=#3\do{\expandafter\zz\expandafter{\listelement}}%
}
\makeatother
%%%%%%%%%%%%%%%%%%%
\DTLloaddb{dbsample}{db-1.csv}
\begin{document}
%First I'm creating my custom comma-separated list, the result of datatool conditions. Can be called using \theback
\def\theback{\DTLforeach*[\DTLisSubString{\Location}{back}]{dbsample}%
{\Name=Name,\Variety=Variety,\Location=Location,\Established=Established}%
{\Name!\Variety, }}
\vspace{10mm}
%%% Now ideally I'd like to have
%\apply{\index}{\theback}
%to work in my table, but it does not. This did not work, I may have to figure out how to set a macro (or definition?) within a macro???
%Next, this is my table.
\begin{table}[htbp]
\caption{Plants that are pre-existing are highlighted in \colorbox{lightmauve}{lightmauve}}
\vspace{5mm}
\centering
\begin{tabular}{lllr}
\bfseries Name &
\bfseries Variety&
\bfseries Location &
\bfseries Established %
\DTLforeach*[\DTLisSubString{\Location}{back}]{dbsample}%
{\Name=Name,\Variety=Variety,\Location=Location,\Established=Established}
{%
\DTLifSubString{\Established}{yes}{\\\rowcolor{lightmauve}}{\\\rowcolor{white}}%
\Name & \Variety & \Location & \Established}
\end{tabular}
\apply{\index}{Daffodil!apricot,St. John's Wort}
%the above will work, but what I'm hoping for is instead, something along the lines of:
%\apply{\index}{\theback}
\end{table}
\printindex % Output the index
\end{document}
抱歉,我不确定我指的东西是否具有正确的名称。任何建议或帮助都将不胜感激。非常感谢!
答案1
正如你在问题的答案中所看到的如何更改 LaTeX 中项目化的“items”之间的间距?,\itemsep
已经在 LaTeX 中定义。
如果您愿意,您可以将非分隔宏参数的交换与旧的\romannumeral
-expansion 结合起来,以定义一个宏,该宏检查的顶层扩展\Variety
是否为空,然后将索引条目所需的内容附加到逗号列表宏(称为) - 我试图在回答这个问题时\theback
解释-expansion\romannumeral
如何知道附加到 csname 宏时的 expandafter 数量?。
在下面的例子中,我决定采用\xdef...{\unexpanded{...}}
-route 来应对\unexpanded
LaTeX 在每次宏扩展时将连续哈希值的数量减半的问题。把这当作一个没有实际意义的观点。;-)
\documentclass[12pt]{book}
\usepackage{datatool}
\usepackage{colortbl}
%necessary to color a table
\definecolor{lightmauve}{rgb}{0.86, 0.82, 1.0}
\usepackage{makeidx} % Required to make an index
\makeindex % Tells LaTeX to create the files required for indexing
\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
{\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Exchange two arguments:
%%.............................................................................
\newcommand\exchangeargs[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Append comma-delimited element to comma-list-macro holding index-entries:
%%.............................................................................
\newcommand\GlobalAppendIndexEntryToCommalist[5]{%
% #1 = comma-list-macro where tokens/index-entries are to be appended
% #2 = !
% #3 = ,
% #4 = \Name
% #5 = \Variety
\xdef#1{%
\unexpanded\expandafter{%
\romannumeral0%
\expandafter\exchangeargs\expandafter{\expandafter{%
\romannumeral0%
\expandafter\CheckWhetherNull\expandafter{#5}{%
\expandafter\exchangeargs\expandafter{#4}{ }%
}{%
\expandafter\exchangeargs\expandafter{#5}{%
\exchangeargs{#2}{%
\expandafter\exchangeargs\expandafter{#4}{ }%
}%
}%
}%
}}{%
\expandafter\CheckWhetherNull\expandafter{#1}{ }{%
\expandafter\exchangeargs\expandafter{#1#3}{ }%
}%
}%
}%
}%
}%
\newcommand*\theback{}%
\newcommand*\GlobalResettheback{\gdef\theback{}}%
% This macro applies a command to each element of a list of comma-separated arguments:
\newcommand{\apply}[2]{%
% #1: command to apply;
% #2: (macro holding) list of comma-separated arguments;
\@for\listelement:=#2\do{%
\expandafter\exchangeargs\expandafter{\expandafter{\listelement}}{#1}%
}%
}%
\makeatother
%%%%%%%%%%%%%%%%%%%
\DTLloaddb{dbsample}{db-1.csv}
\begin{document}
%This is my table.
\begin{table}[htbp]
\caption{Plants that are pre-existing are highlighted in \colorbox{lightmauve}{lightmauve}}
\vspace{5mm}%
\centering
\GlobalResettheback
\begin{tabular}{lllr}
\bfseries Name &
\bfseries Variety&
\bfseries Location &
\bfseries Established %
\DTLforeach*[\DTLisSubString{\Location}{back}]{dbsample}%
{\Name=Name,\Variety=Variety,\Location=Location,\Established=Established}
{%
\DTLifSubString{\Established}{yes}{\\\rowcolor{lightmauve}}{\\\rowcolor{white}}%
\Name & \Variety & \Location & \Established%
\GlobalAppendIndexEntryToCommalist{\theback}{!}{,}{\Name}{\Variety}%
}%
\end{tabular}
%
%\apply{\index}{Daffodil!apricot,St. John's Wort}
%\show\theback
\apply{\index}{\theback}
%
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
% Be aware:
%
% If you decide to have tables not as floating objects but as part of the
% main text and switch to tabularx for having multipage-tables, then
% carrying out all \index-commands _after_ already having shipped all pages
% of the table may yield wrong page-numbers with index-entries of things
% that do not occur on the last page of the table but do occur on pages
% prior to that last page.
%
% That's why below I added a suggestion where index-entries are produced
% and \index-commands are carried out at the time of producing the
% table-rows via \DTLforeach*.
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
%
\end{table}
\printindex % Output the index
\end{document}
可能您不需要维护这样的逗号列表宏,但可以让 LaTeX\DTLforeach*
直接从循环中构建索引条目:
\documentclass[12pt]{book}
\usepackage{datatool}
\usepackage{colortbl}
%necessary to color a table
\definecolor{lightmauve}{rgb}{0.86, 0.82, 1.0}
\usepackage{makeidx} % Required to make an index
\makeindex % Tells LaTeX to create the files required for indexing
\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
{\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Exchange two arguments:
%%.............................................................................
\newcommand\exchangeargs[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Construct index-entry from \Name and \Variety
%%.............................................................................
\newcommand\ConstructIndexentry[4]{%
% #1 = indexing-command, usually \index
% #2 = !
% #3 = \Name
% #4 = \Variety
\expandafter\exchangeargs\expandafter{\expandafter{%
\romannumeral0%
\expandafter\CheckWhetherNull\expandafter{#4}{%
\expandafter\exchangeargs\expandafter{#3}{ }%
}{%
\expandafter\exchangeargs\expandafter{#4}{%
\exchangeargs{#2}{%
\expandafter\exchangeargs\expandafter{#3}{ }%
}%
}%
}%
}}{#1}%
}%
\makeatother
\DTLloaddb{dbsample}{db-1.csv}
\begin{document}
%This is the table.
\begin{table}[htbp]
\caption{Plants that are pre-existing are highlighted in \colorbox{lightmauve}{lightmauve}}
\vspace{5mm}%
\centering
\begin{tabular}{lllr}
\bfseries Name &
\bfseries Variety&
\bfseries Location &
\bfseries Established %
\DTLforeach*[\DTLisSubString{\Location}{back}]{dbsample}%
{\Name=Name,\Variety=Variety,\Location=Location,\Established=Established}
{%
\DTLifSubString{\Established}{yes}{\\\rowcolor{lightmauve}}{\\\rowcolor{white}}%
\Name & \Variety & \Location & \Established%
\ConstructIndexentry{\index}{!}{\Name}{\Variety}%
}%
\end{tabular}
\end{table}
\printindex % Output the index
\end{document}