\if测试说明

\if测试说明

我对 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 — 正如您所观察到的。\tempb0.0pt0.\if

摘要:您想以某种方式比较\tempb\tempa,但实际上您从扩展的前面比较了0和,其余部分留在了的开头.\tempb0pt\tempa真实条款测试\if,因此在这里被忽略,因为测试为假(TeX 将跳过标记而不扩展任何内容,直到找到匹配的\else\fi)。

如何比较长度和字符串

在 LaTeX 中,有很多方法可以比较长度和字符串。以下是使用ifthenetoolbox包的一些示例。您可能还会对xifthen和感兴趣expl3(好吧,对于后者来说可能还为时过早,但它非常强大且方便)。

ifthen和之间一个值得注意的区别是,来自包的etoolbox字符串相等性测试递归地扩展了它的参数,但不会更改类别代码,而来自包的测试不会扩展它的参数,但会规范化类别代码(\equalifthen\ifstrequaletoolbox先验使用\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。顺便说一下,这种分配类别代码的方式在语言中称为“转换为字符串” 。pt\the\test0.0ptifthen\equal\test0.0pt\the\test\detokenize{0.0pt}\equalifthen\test0.0pt\the\detokenizeexpl3

以下是该包的示例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}

使用 etoolbox 的示例

最后,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}

使用 ifthen 的示例


脚注

  1. 你可以通过扩展来获得空间标记,\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扩展为

012 .12 012 p11 t11

\tempa扩展为

012 .12 012 p12 t12

(下标表示类别代码),因为\tempa定义为\the 参见https://tex.stackexchange.com/a/38680/4427原因。为了\ifx返回 true,两个宏必须扩展为相同的文本逐个标记而这两个宏却没有。

另一方面,\ifdim比较两个维度并扩展以下标记,直到找到以下形式

<dimen> <comparator> <dimen>

其中是121212<comparator>中的一个(两边可以有空格)。必须是显式维度,例如或隐式维度(维度寄存器)。在显式维度中,表示单位的两个字母(这是强制性的)可以是类别代码 11 或 12。因此,您的变成<=><dimen>0.0pt\ifdim\tempb=\tempa

\ifdim 012 .12 012 p11 t11 12 12 12 =12 12 120 . 0 p t

并返回 true。

你能比较字符串吗?是的。有一个“类别代码不可知”测试:

\ifnum\pdfstrcmp{\tempb}{\tempa}=0

将返回 true。请注意,这\pdfstrcmp\strcmpXeTeX 中的,LuaTeX 中不存在,但我们可以使用以下命令获得适用于所有已知引擎的版本:

\usepackage{pdftexcmds}

或者\input pdftexcmds.sty用普通的 TeX,这样你就可以使用

\ifnum\pdf@strcmp{\tempb}{\tempa}=0

(当然是在@类别代码为 11 的环境中);\pdf@strcmp将被转换为适合当前引擎的原语(或 Lua 函数)。

或者您可以使用etoolbox或的更高级别的方法expl3

相关内容