我正在寻找一种实现具有switch/case
控制结构(或array
解决方案)的宏的方法,因为它存在于每种编程语言中。
梅威瑟:
\documentclass[ngerman,12pt]{article}
\usepackage{etoolbox}
\newcommand*\foo[1]{%
\ifstrequal{#1}{givemea}{box}{}%
\ifstrequal{#1}{drawmea}{circle}{}%
\ifstrequal{#1}{applesidontlikeare}{green}{}%
\ifstrequal{#1}{life}{is full of surprises}{}%
}
\begin{document}
\foo{life}
\end{document}
你可以想象,如果我有 500 个条目,这个过程会非常慢,因为它与每一个价值在宏中。\break
或\return
命令非常有用,因此如果找到该值,宏将中止。另外:我的字符串也将包含数字(在每个位置)。
或者有没有什么软件包可以用于这项工作?
(由于会有很多条目,我考虑将一个宏分成多个:\fooa
,,\foob
...所以,如果我调用\foo{life}
它,会检查第一个字母l
,然后调用\fool{life}
。这也会加快这个过程。)
答案1
您不需要进行一系列线性的字符串相等性测试,而需要进行哈希查找:
\documentclass[12pt]{article}
\newcommand*\foo[1]{\csname FOO-#1\endcsname}
\newcommand*\setfoo[1]{\expandafter\def\csname FOO-#1\endcsname}
\setfoo{give1mea}{box}
\setfoo{draw2mea}{circle}
\setfoo{applesidontlikeare!!}{green}
\setfoo{life}{is full of surprises}
\setfoo{apple4dinner}{see?}
\begin{document}
\foo{life} \foo{apple4dinner}
\end{document}
答案2
expl3
LaTeX3 的编程层提供了相关\str_case:nnF
功能:这些仅比较“所需的范围”:
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_eq:NN \strcases \str_case:nnF
\ExplSyntaxOff
\newcommand*\foo[1]{%
\strcases{#1}%
{%
{givemea} {box}
{drawmea} {circle}
{applesidontlikeare}{green}
{life} {is full of surprises}
}%
{No match found!}%
}
\begin{document}
\foo{life}
\end{document}
请注意,对于非常长的列表,仍然必须对每个项目进行比较,直到找到匹配项,当项目接近末尾时,对于非常长的列表,比较速度会变慢。
另一种方法,类似于大卫的在使用查找表的意义上,就是使用prop
:
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\prop_new:N \l_my_prop
\prop_put:Nnn \l_my_prop {givemea} {box}
\prop_put:Nnn \l_my_prop {drawmea} {circle}
\prop_put:Nnn \l_my_prop {applesidontlikeare}{green}
\prop_put:Nnn \l_my_prop {life} {is~full~of~surprises}
\newcommand* \foo [1]
{
\prop_get:NnNTF \l_my_prop {#1} \l_tmpa_tl
{ \tl_use:N \l_tmpa_tl }
{ No~match~found! }
}
\ExplSyntaxOff
\begin{document}
\foo{life}
\end{document}
此处的数据结构(目前)仅使用一个名称,但这意味着随着大小的增加,添加会相对较慢。但是,查找应该不会受到如此严重的影响(它使用分隔宏),尽管随着表大小的增加,查找也会下降。(对于“大”数据集,TeX 的哈希表可能是创建查找系统的最佳方式,如 David 的回答中所述。请参阅如何在 TeX 中实现(低级)数组了解更多。
答案3
以下示例比较字符串,直到找到匹配项。然后\@car
获取第一个参数并抛出其余部分直到下一个参数\@nil
,以便跳过以下比较:
\documentclass[12pt]{article}
\usepackage{etoolbox}
\makeatletter
\newcommand*\foo[1]{%
\def\foo@##1##2{%
\ifstrequal{#1}{##1}{\@car{##2}}{}%
}%
\foo@{givemea}{box}%
\foo@{drawmea}{circle}%
\foo@{applesidontlikeare}{green}%
\foo@{life}{is full of surprises}%
\@nil
}
\makeatother
\begin{document}
\foo{givemea} \foo{life}
\end{document}