我对 LaTeX 还很陌生,需要将我定义的长度与默认值进行比较(并相应地设置另一个长度)。因此,我正在探索 LaTeX 条件的模糊世界(至少对我来说是这样)。
有人能向我解释为什么,在下面,\ifdim
产生了预期的行为,但\if
没有,即使我\test
在进行比较之前扩展到一些文本?据我了解,\if
它应该扩展标记,直到有两个不能再扩展的标记,然后对它们进行操作 - 这难道不应该意味着它会0.0pt
与(作为文本)进行比较0.0pt
并评估为真吗?
\newlength\test
\setlength\test{0.0pt}
\edef\tempa{\the\test}
\edef\tempb{0.0pt}
% this would evaluate false, even though \tempa and \tempb both print 0.0pt when expanded
\if\tempb\tempa
% this works
\ifdim\tempb=\tempa
{
Using max width
}
\else
{
Using assigned width (\the\test)
\typeout{Tempa is \tempa ; Tempb is \tempb ;}
}
\fi
如果我确实想比较存储在\tempa
和中的字符序列,我应该如何进行这些类型的比较\tempb
?有没有办法完全避免分配临时变量?理想情况下,毕竟,我想要:
\ifthenelse{\equals{\the\test}{0.0pt}}
{
True
}
{
False
}
但是当我尝试的时候它也没有用!
答案1
如果你是“LaTeX 新手”,这些内容可能比较难。花点时间了解标记、字符代码、类别代码、扩展等。TeXbook 是了解所有这些内容的一个很好的参考资料。
\if
测试说明
TeX 基元\if
递归扩展输入流中的内容,直到有两个不可扩展的标记。如果这些标记都是字符标记(正如我们将在下面看到的示例中的情况),则\if
当且仅当字符标记具有相同的字符代码时,测试才为真。这听起来可能不太明显,但这就是\if
工作原理:它比较字符代码。
(其他著名的测试有\ifcat
比较类别代码、\ifnum
比较〈number〉、\ifdim
比较〈dimen〉和\ifx
比较两个标记的含义。)
在你的情况下,你有\if\tempb\tempa...
。\if
根据上述描述执行一个扩展步骤后,输入流的前面是0.0pt\tempa...
。因此,您的代码的行为与此相同:
\if 0.0pt\tempa...
\if0.0pt\tempa...
(由于第一个0
不是字母,因此与 相同)。
因此,在 自动执行此扩展步骤之后\if
,输入流中已经有两个不可扩展标记:0
和.
,两者的类别代码均为 12(其他),因为它们来自,其中( )\edef\tempb{0.0pt}
的替换文本已根据标准类别代码机制进行标记化。因此,TeX 会比较和的字符代码,它们显然不同(参见 ASCII 代码表),因此测试结果为 false — 正如您所观察到的。\tempb
0.0pt
0
.
\if
摘要:您想以某种方式比较\tempb
和\tempa
,但实际上您从扩展的前面比较了0
和,其余部分留在了的开头.
\tempb
0pt\tempa
真实条款测试\if
,因此在这里被忽略,因为测试为假(TeX 将跳过标记而不扩展任何内容,直到找到匹配的\else
或\fi
)。
如何比较长度和字符串
在 LaTeX 中,有很多方法可以比较长度和字符串。以下是使用ifthen
和etoolbox
包的一些示例。您可能还会对xifthen
和感兴趣expl3
(好吧,对于后者来说可能还为时过早,但它非常强大且方便)。
ifthen
和之间一个值得注意的区别是,来自包的etoolbox
字符串相等性测试递归地扩展了它的参数,但不会更改类别代码,而来自包的测试不会扩展它的参数,但会规范化类别代码(\equal
ifthen
\ifstrequal
etoolbox
先验使用\detokenize
)。这非常重要,因为当\test
是 〈dimendef token〉 或 〈skipdef token〉 时(这里的情况),\the\test
会扩展为类别代码为 12(其他)的字符 token,但空格 token 除外,因为空格 token 的类别代码为 10(空格)。“所有类别代码 12”中的1是 0.0pt
不一样0.0pt
与使用标准类别代码进行标记的结果相同,即: 和 为 12 ,0
和为.
11(字母)。这就是为什么使用 的“字符串”相等性测试与使用标准类别代码进行标记的结果进行比较,即使已设置为,也会产生 false 。但是,如果我们使用包 的相同比较函数与进行比较,则当已设置为时结果为 true ,因为和都以完全相同的方式为它们扩展为的字符标记分配类别代码 - 即,除空格外,每个字符标记都为 12,空格为 10。顺便说一下,这种分配类别代码的方式在语言中称为“转换为字符串” 。p
t
\the\test
0.0pt
ifthen
\equal
\test
0.0pt
\the\test
\detokenize{0.0pt}
\equal
ifthen
\test
0.0pt
\the
\detokenize
expl3
以下是该包的示例etoolbox
:
\documentclass{article}
\usepackage{etoolbox}
\newlength{\test}
\setlength{\parindent}{0pt}
\begin{document}
\setlength{\test}{0pt}
Length comparisons:\\
1. \ifdimcomp{\test}{=}{0.0pt}{Equal}{Not equal}\\
2. \ifdimcomp{\test}{=}{0pt}{Equal}{Not equal}
\bigskip
String comparisons (\verb|\the\test| expands to \the\test):\\
3. \ifstrequal{\the\test}{0.0pt}{Equal}{Not equal}\\
4. \expandafter\ifstrequal\expandafter{\the\test}{0.0pt}{Equal}{Not equal}
\bigskip
\setlength{\test}{0.1pt}
Length then string comparison with \verb|0.1pt|:\\
5. \ifdimcomp{\test}{=}{0.0pt}{Equal}{Not equal}\\
6. \expandafter\ifstrequal\expandafter{\the\test}{0.0pt}{Equal}{Not equal}
\end{document}
最后,ifthen
软件包中承诺的示例如下:
\documentclass{article}
\usepackage{ifthen}
\newlength{\test}
\setlength{\parindent}{0pt}
\begin{document}
\setlength{\test}{0pt}
Length comparisons:\\
1. \ifthenelse{\lengthtest{\test=0.0pt}}{Equal}{Not equal}\\
2. \ifthenelse{\lengthtest{\test=0pt}}{Equal}{Not equal}
\bigskip
String comparisons (\verb|\the\test| expands to \the\test):\\
3. \ifthenelse{\equal{\the\test}{0.0pt}}{Equal}{Not equal}\\
4. \ifthenelse{\equal{\the\test}{\detokenize{0.0pt}}}{Equal}{Not equal}\\
5. \ifthenelse{\equal{\the\test}{\detokenize{0pt}}}{Equal}{Not equal}
\bigskip
\setlength{\test}{0.1pt}
Length then string comparison with \verb|0.1pt|:\\
6. \ifthenelse{\lengthtest{\test=0.0pt}}{Equal}{Not equal}\\
7. \ifthenelse{\equal{\the\test}{0.0pt}}{Equal}{Not equal}
\end{document}
脚注
你可以通过扩展来获得空间标记,
\the\test
例如:\newlength{\test}% \setlength{\test}{0.1pt plus 3pt minus 1pt}
执行此操作后,使用expl3
的\tl_analysis_show:n
函数分析 扩展中的每个标记\the\test
:
```latex
\documentclass{article}
\usepackage{expl3}
\newlength{\test}
\setlength{\test}{0.1pt plus 3pt minus 1pt}
\ExplSyntaxOn
\cs_generate_variant:Nn \tl_analysis_show:n { o }
% One expansion step on \the\test, result passed to \tl_analysis_show:n
\tl_analysis_show:o { \the\test }
\ExplSyntaxOff
\begin{document}
\end{document}
```
在终端上产生以下输出:
```none
> 0 (the character 0)
> . (the character .)
> 1 (the character 1)
> p (the character p)
> t (the character t)
> (blank space )
> p (the character p)
> l (the character l)
> u (the character u)
> s (the character s)
> (blank space )
> 3 (the character 3)
> . (the character .)
> 0 (the character 0)
> p (the character p)
> t (the character t)
> (blank space )
> m (the character m)
> i (the character i)
> n (the character n)
> u (the character u)
> s (the character s)
> (blank space )
> 1 (the character 1)
> . (the character .)
> 0 (the character 0)
> p (the character p)
> t (the character t).
```
答案2
首先,TeX 中的条件语句不需要在“真”和“假”分支周围使用括号。如果使用嵌套条件,括号会形成组,甚至可能破坏所有内容,但不仅仅是在这种情况下。
现在谈谈理论。条件语句\if
会扩展其后的 token,直到找到二不可扩展标记,然后通过字符代码进行比较。
所以你的情况
\if\tempb\tempa
变成
\if0.0pt\tempa
并且 TeX0
与进行比较.
,发现它们不同,因此遵循“假分支”并0pt\tempa
成为“真分支”的一部分,因此被忽略。
如果你想比较两个宏的含义,你可以使用\ifx
,但是…是的,测试
\ifx\tempb\tempa
返回 false。TeX 比较两个宏的第一级扩展,但它们不同的。事实上,\tempb
扩展为
0
12 .
12 0
12 p
11 t
11
而\tempa
扩展为
0
12 .
12 0
12 p
12 t
12
(下标表示类别代码),因为\tempa
定义为\the
参见https://tex.stackexchange.com/a/38680/4427原因。为了\ifx
返回 true,两个宏必须扩展为相同的文本逐个标记而这两个宏却没有。
另一方面,\ifdim
比较两个维度并扩展以下标记,直到找到以下形式
<dimen> <comparator> <dimen>
其中是12、12或12<comparator>
中的一个(两边可以有空格)。必须是显式维度,例如或隐式维度(维度寄存器)。在显式维度中,表示单位的两个字母(这是强制性的)可以是类别代码 11 或 12。因此,您的变成<
=
>
<dimen>
0.0pt
\ifdim\tempb=\tempa
\ifdim
0
12 .
12 0
12 p
11 t
11 12 12 12 =
12 12 120
.
0
p
t
并返回 true。
你能比较字符串吗?是的。有一个“类别代码不可知”测试:
\ifnum\pdfstrcmp{\tempb}{\tempa}=0
将返回 true。请注意,这\pdfstrcmp
是\strcmp
XeTeX 中的,LuaTeX 中不存在,但我们可以使用以下命令获得适用于所有已知引擎的版本:
\usepackage{pdftexcmds}
或者\input pdftexcmds.sty
用普通的 TeX,这样你就可以使用
\ifnum\pdf@strcmp{\tempb}{\tempa}=0
(当然是在@
类别代码为 11 的环境中);\pdf@strcmp
将被转换为适合当前引擎的原语(或 Lua 函数)。
或者您可以使用etoolbox
或的更高级别的方法expl3
。