我想在 LaTeX 中实现一个简单的关联列表。我的想法是,我可以输入\branch|Some arbitrary !_{} text here|
,它将Some arbitrary !_{} text here
在 (静态) 映射表中查找string → string
并根据需要进行替换。
有两个棘手的方面:
解析命令的逐字参数。为此,我可以使用
xparse
及其\NewDocumentCommand
。实现关联列表。为此我可以使用嵌套
\ifstrequal
命令。
不过,我不确定如何将两者结合起来。这是一个 MWE;它适用于关联列表AAA → "Found some As", BBB → "Found some Bs"
:
\documentclass{article}
\usepackage[english]{babel}
\usepackage{etoolbox}
\usepackage{xparse}
\NewDocumentCommand\branch{v}{%
\ifstrequal{#1}{AAA}{Found some As!}{%
\ifstrequal{#1}{BBB}{Found some Bs!}{%
Key not found: \texttt{#1}!}}}
\begin{document}
\branch|AA|\\
\branch|AAA|\\
\branch/BBB/\\
\branch!BB!
\branch|AA!}/|
\branch|BB!\/:|
\end{document}
我应该如何修改这个 MWE 来添加最后两个键(AA!}/
和BB!\/:
)的映射?虽然我的\branch
命令可以很好地解析它们,但我不知道将逐字字符串传递给的优雅方法\ifstrequal
。我目前最好的方法是:
\NewDocumentCommand\MakeTable{v v v v}{%
\NewDocumentCommand\fancybranch{v}{%
\ifstrequal{##1}{#1}{Found some As!}{%
\ifstrequal{##1}{#2}{Found some Bs!}{%
\ifstrequal{##1}{#3}{Found some weird As!}{%
\ifstrequal{##1}{#4}{Found some weird Bs!}{%
Key not found: \texttt{#1}!}}}}}}
\MakeTable|AAA||BBB||AA!}/||BB!\/:|
这让我可以使用\fancybranch
而不是branch
,一切看起来都很好,但看起来不太优雅;欢迎提出建议。有没有更好的方法来实现这个? 使用etoolbox
和xparse
依赖这个\MakeTable
宏看起来有点重量级(另一方面,代码本身就相当易读)。
答案1
由于您评论说可能会有更轻量级的版本,即无软件包版本,请注意,这使用 csname 哈希表来查找项目,而不是通过列表进行线性搜索。
\documentclass{article}
\makeatletter
\def\branch{%
\begingroup
\let\do\@makeother\dospecials
\xxbranch}
\def\xxbranch#1{\def\tmp##1#1{\endgroup\xbranch{##1}}\tmp}
\def\xbranch#1{%
\expandafter\ifx\csname X-\detokenize{#1}\endcsname\relax
\texttt{\detokenize{#1}} Not found%
\else
\csname X-\detokenize{#1}\expandafter\endcsname
\fi}
\def\defbranch{%
\begingroup
\let\do\@makeother\dospecials
\xxdefbranch}
\def\xxdefbranch#1{\def\tmp##1#1{\endgroup\xdefbranch{##1}}\tmp}
\def\xdefbranch#1{\expandafter\def\csname X-\detokenize{#1}\endcsname}
\defbranch|AAA|{Found some As!}
\defbranch|BBB|{Found some Bs!}
\defbranch|AA!}/|{Found some weird As!}
\defbranch|BB!\/:|{Found some weird Bs!}
\begin{document}
\branch|AA|\\
\branch|AAA|\\
\branch/BBB/\\
\branch!BB!
\branch|AA!}/|
\branch|BB!\/:|
\end{document}
答案2
充分利用expl3
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand\branch{v}
{
\clement_branch:n { #1 }
}
\cs_new_protected:Nn \clement_branch:n
{
\str_case_x:nnF { #1 }
{
{AAA}{Found~some~As!}
{BBB}{Found~some~Bs!}
{AA!\c_right_brace_str/}{Found~some~weird~As!}
{BB!\c_backslash_str/:}{Found~some~weird~Bs!}
}
{Key~not~found~\texttt{#1}!}
}
\ExplSyntaxOff
\begin{document}
1. \branch|AA|
2. \branch|AAA|
3. \branch/BBB/
4. \branch!BB!
5. \branch|AA!}/|
6. \branch|BB!\/:|
\end{document}
一种可以更容易地定义各个分支的替代方法。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand\branch{v}
{
\clement_branch:n { #1 }
}
\NewDocumentCommand{\definebranch}{vm}
{
\prop_gput:Nnn \g_clement_branches_prop { #1 } { #2 }
}
\cs_new_protected:Nn \clement_branch:n
{
\prop_get:NnN \g_clement_branches_prop { #1 } \l__clement_branch_temp_tl
\quark_if_no_value:VTF \l__clement_branch_temp_tl
{ Key~not~found~\texttt{#1}! }
{ \tl_use:N \l__clement_branch_temp_tl }
}
\cs_generate_variant:Nn \quark_if_no_value:nTF { V }
\prop_new:N \g_clement_branches_prop
\tl_new:N \l__clement_branch_temp_tl
\ExplSyntaxOff
\definebranch|AAA|{Found some As!}
\definebranch|BBB|{Found some Bs!}
\definebranch|AA!}/|{Found some weird As!}
\definebranch|BB!\/:|{Found some weird Bs!}
\begin{document}
1. \branch|AA|
2. \branch|AAA|
3. \branch/BBB/
4. \branch!BB!
5. \branch|AA!}/|
6. \branch|BB!\/:|
\end{document}