\pgfmathsetlengthmacro 与循环不兼容?

\pgfmathsetlengthmacro 与循环不兼容?

以下代码可以完美编译:

\documentclass[]{article}

\usepackage[most]{tcolorbox}

\newcommand\UseImageLeft[1]{%
\IfFileExists{#1\i.jpg}%
  {\includegraphics[scale=0.2]{#1\i.jpg}}%
    {\includegraphics[scale=0.2]{example-image.jpg}}%
}

\def\ImageLeft{\UseImageLeft{Image-}}

% Problem ===================================
% \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================

\begin{document}

\foreach \i in {1,...,2}{

% On any page (begin)
\begin{tcolorbox}[]
\begin{tcbitemize}[]
\tcbitem[] \ImageLeft
\end{tcbitemize}
\end{tcolorbox}
% On any page (end)

\newpage
}

\end{document}

我的问题是我想取消注释\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")},但代码无法再编译。请问我该如何修复这个问题?

答案1

问题 1:

你用\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")} 外部-loop \foreach。但是使用\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}\ImageLeft,它又使用宏,\UseImageLeft它又使用宏,\i而宏\i的定义只产生图像的数量之内-循环\foreach

问题2:

你有\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}哪种图案

\pgfmathsetlengthmacro\LeftWidth{⟨expression⟩}
带有
⟨expression⟩ = width("\ImageLeft")
,而
width("\ImageLeft")
反过来又是 带有 = 的模式。
width(⟨expression⟩)

⟨expression⟩"\ImageLeft"

这意味着将其\ImageLeft作为两次的一部分进行评估⟨expression⟩

第一次对⟨expression⟩形成的论点\pgfmathsetlengthmacro\LeftWidth进行评估。

第二次对⟨expression⟩形成的论点width(...)进行评估。

pgfmanual.pdf,“95.2 数学表达式的语法:运算符”一节在 -operator 的解释中说:"x"

... 然而,由于每个表达式在解析之前都用 \edef 进行扩展,因此宏(例如,字体命令 \tt 或 \Huge)可能需要“保护”以免受到此扩展(例如,\noexpand\Huge)。理想情况下,你应该避免使用此类宏。显然,使用这些运算符时应格外小心,因为结果不太可能进行进一步的计算。

此信息不仅与-operator 相关。"x"无论何时评估,这些信息都是相关的⟨expression⟩ 这是在评估每个 时应用的一般规则⟨expression⟩。因此,我认为仅在解释特殊运算符时传达此信息不是一个好主意。

是因为它可能:

将这些信息放在一起,您会发现\ImageLeft通过 进行两次评估\edef。由于扩展链是\ImageLeft\UseImageLeft→ ,这意味着通过进行...\includegraphics...两次评估尝试。 但如果您不使用最新的 TeX 发行版之一,则在 -expansion-contexts 中不起作用。这是因为在较旧的 TeX 发行版中,不受“保护”——“受保护”是指 LaTeX 内部机制,用于在扩展不起作用的情况下防止命令扩展——并且“依赖于”执行临时分配,例如,就 而言,而在-evaluation 正在进行时不会执行此类分配。触发可扩展标记的扩展,而是不可扩展的原语。\includegraphics\edef
\includegraphics\edef\includegraphics\def\edef\edef\def

因此,如果您不使用最新的 TeX 发行版之一,则需要采取预防措施,以防止在每个-evaluations 中扩展/评估命令\ImageLeft(从而也防止扩展/评估) 。 (在最新的 TeX 发行版中,这些预防措施既不麻烦也不是必需的。)\includegraphics\edef

您可以通过在前面加上 来阻止扩展/\ImageLeft评估\noexpand\noexpand\noexpand

第一个\edef- 求值应用于<code>\noexpand\noexpand\noexpand\ImageLeft</code>
得出
<code>\noexpand\ImageLeft</code>
第二个\edef- 求值将应用于 ,从而得出:
<code>\ImageLeft</code>

问题3:

egreg 指出\iLaTeX 中已经定义了 ,您可能不想覆盖该定义。因此在下面的示例中,我使用了\NiceForEachElement而不是\i

\documentclass[]{article}

\usepackage[most]{tcolorbox}

\newcommand\UseImageLeft[1]{%
\IfFileExists{#1\NiceForEachElement.jpg}%
  {\includegraphics[scale=0.2]{#1\NiceForEachElement.jpg}}%
    {\includegraphics[scale=0.2]{example-image.jpg}}%
}

\def\ImageLeft{\UseImageLeft{Image-}}

% Problem ===================================
%\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================

\begin{document}

\foreach \NiceForEachElement in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% On any page (begin)
\begin{tcolorbox}[]%
\begin{tcbitemize}[]%
\tcbitem[] \ImageLeft
\end{tcbitemize}%
\end{tcolorbox}%
% On any page (end)
\newpage
}

\end{document}

\ImageLeft如果您希望在循环外部也能使用,则定义\ImageLeftetc 来处理参数而不是处理\i/ \NiceForEachElement
在循环内部,您可以将\i/\NiceForEachElement作为参数传递。
在循环外部,您可以直接将图像编号作为参数传递。

\documentclass[]{article}

\usepackage[most]{tcolorbox}

% Define the command \NiceForEachElement to ensure error-message in case it is already defined.
% This way you can ensure to a certain degree that using `\niceelement` as Foreach-variable
% does not override something that alerady exists.
\newcommand\NiceForEachElement{}%

\newcommand\UseImageLeft[2]{%
% #1 preceding phrase "image-"
% #2 number of image
\IfFileExists{#1#2.jpg}%
  {\includegraphics[scale=0.2]{#1#2.jpg}}%
    {\includegraphics[scale=0.2]{example-image.jpg}}%
}

\newcommand*\ImageLeft[1]{\UseImageLeft{Image-}{#1}}

% Problem ===================================
%\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================

\begin{document}

% outside the loop the width of Image-7.jpg or example-image.jpg:

\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{7}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth

% inside the loop:

\foreach \NiceForEachElement in {1,...,2}{%
  \pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{\NiceForEachElement}")}%
  %Activate the following line in case you wish to see on screen/console  what the definition of \LeftWidth looks like now:
  %\show\LeftWidth
  % On any page (begin)
  \begin{tcolorbox}[]%
  \begin{tcbitemize}[]%
  \tcbitem[] \ImageLeft{\NiceForEachElement}%
  \end{tcbitemize}%
  \end{tcolorbox}%
  % On any page (end)
  \newpage
}

\end{document}

答案2

不要在循环外使用循环变量,无论是在执行的代码中还是在定义中。

\documentclass[]{article}

\usepackage[most]{tcolorbox}

\newcommand\UseImageLeft[1]{%
\IfFileExists{#1.jpg}%
  {\includegraphics[scale=0.2]{#1.jpg}}%
  {\includegraphics[scale=0.2]{example-image.jpg}}%
}


\begin{document}

\foreach \i in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\UseImageLeft{image\i}")}%
% On any page (begin)
\begin{tcolorbox}[]
\begin{tcbitemize}[]
\tcbitem[] \UseImageLeft{image\i}
\end{tcbitemize}
\end{tcolorbox}
% On any page (end)

\newpage
}^

\end{document}

相关内容