以下代码可以完美编译:
\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 指出\i
LaTeX 中已经定义了 ,您可能不想覆盖该定义。因此在下面的示例中,我使用了\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
如果您希望在循环外部也能使用,则定义\ImageLeft
etc 来处理参数而不是处理\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}