如何使用 `\ifstrequal` 从 `\foreach` 变量中“解复用”多个方面?

如何使用 `\ifstrequal` 从 `\foreach` 变量中“解复用”多个方面?

我怎样才能从给定的模式规范中“解复用”几个功能\foreach

我想使用 来\foreach绘制 TikZ 图片中的多个节点。循环将为每个节点指定一个模式,反过来,该模式将用于设置节点样式和位置的几个特征。由于模式指定了一组特征,我想从模式规范中“分离”这些特征,而不是必须在 中列出每个特征\foreach。一个最小的不起作用的例子是

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}

\begin{document}
\begin{tikzpicture}
  \foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
  {
    \edef\myscale{\ifstrequal{\mode}{large}{1}{0.25}}
    \edef\mycolor{\ifstrequal{\mode}{large}{black}{gray}}

    \typeout{\meaning\myscale}
    \typeout{\meaning\mycolor}
    \node [scale=\myscale, color=\mycolor, draw] at \loc {\myscale\mycolor};
  }
\end{tikzpicture}
\end{document}

如果我尝试编译它,我会得到错误! Package xcolor Error: Undefined color \ifstrequal{small}{large}{black}{gray}.

似乎在将条件传递给样式之前需要对其进行扩展,但我不知道该怎么做。令人惊讶的是(至少对我来说),如果我scale=\myscale, color=\mycolor从样式中删除,那么我会得到以下输出。

在此处输入图片描述

因此,由于某种原因,节点文本扩展了条件,但样式却没有。

另外问一下:为什么我帖子里的图片总是变那么小?)

编辑:看起来,\foreach上面的错误信息有点让人分心。具体来说,以下更简单的代码会产生相同的错误:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}

\begin{document}
\def\mode{small}%
\begin{tikzpicture}
  \node [scale=\ifstrequal{\mode}{large}{1}{0.25}, draw]
        {\ifstrequal{\mode}{large}{1}{0.25}};
\end{tikzpicture}
\end{document}

尽管@percusse 的答案最适合我的特定用途,但我仍然想知道为什么会出现此错误。此外,是否可以强制扩展\ifstrequal

答案1

在 foreach 列表中扩展通常会有问题,需要在正确的位置执行。以下是一些示例

TikZ 矩阵中行和列的嵌套 foreach

Tikz foreach 矩阵内部

还建议使用样式定义键以避免此类问题。

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\tikzset{l/.style={scale=1,black},s/.style={scale=0.25,gray}}
\foreach \mode/\loc in {s/{(0,0)}, l/{(2,0)}}{
    \node [\mode] at \loc {\mode};
  }
\end{tikzpicture}
\end{document}

在此处输入图片描述

我还会避免使用文字来定义样式和变量,因为任何其他包也可以定义相同的样式和变量,这会导致不必要的调试工作。

答案2

不确定发生了什么\ifstrequal,但你可以使用\IfStrEq来自 包裹xstring

\IfStrEq{\mode}{large}{%
    \gdef\myscale{1}%
    \gdef\mycolor{black}%
}{%
    \gdef\myscale{0.25}%
    \gdef\mycolor{gray}%
}%

生成结果:

在此处输入图片描述

代码:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xstring}

\begin{document}
\begin{tikzpicture}
  \foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
  {
    \IfStrEq{\mode}{large}{%
        \gdef\myscale{1}%
        \gdef\mycolor{black}%
    }{%
        \gdef\myscale{0.25}%
        \gdef\mycolor{gray}%
    }%

    \node [scale=\myscale, color=\mycolor, draw] at \loc {\myscale\mycolor};
  }
\end{tikzpicture}
\end{document}

我实际上建议您使用\tikzset来定义样式:

\IfStrEq{\mode}{large}{%
    \tikzset{MyStyle/.style={scale=1, color=black}}
}{%
    \tikzset{MyStyle/.style={scale=0.25, color=gray}}
}%

产生与上面相同的结果。

代码:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xstring}

\begin{document}
\begin{tikzpicture}
  \foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
  {
    \IfStrEq{\mode}{large}{%
        \tikzset{MyStyle/.style={scale=1, color=black}}
    }{%
        \tikzset{MyStyle/.style={scale=0.25, color=gray}}
    }%

    \node [MyStyle, draw] at \loc {\myscale\mycolor};
  }
\end{tikzpicture}
\end{document}

答案3

或许这在技术上不能回答您的问题\ifstrequal,但提供了一种解决方法。您可以使用不同的(更原始的)方法进行调节\ifx...\else...\fi

\def\mystring{large}%
\ifx\mode\mystring
  \def\myscale{1}%
  \def\mycolor{black}%
\else% \mode is not large
  \def\myscale{0.25}%
  \def\mycolor{gray}%
\fi%

在此处输入图片描述

相关内容