狡猾的 (La)TeX 技巧

狡猾的 (La)TeX 技巧

编写 (La)TeX 代码有时需要一定的技巧。以下是我最喜欢的两个示例(无特定顺序)。

以空格结尾的宏

皮特问如何看待\LaTeX,因为\show\LaTeX结果是\protect \LaTeX。Joseph Wright 的建议让我很开心。(我可能应该尝试多出去走走)。

\let\protect\show
\LaTeX

将变量大写

我问如何存储变量中字符串的大写对应部分, 因为

\def\word{abc}
\def\WORD{\MakeUppercase{\word}}
\show\WORD

返回\MakeUppercase {abc}。Bruno Le Floch 提供了一个极好的解决方案。

\MakeUppercase{\gdef\noexpand\WORD{\word}}

您最喜欢的 (La)TeX 巧妙技巧是什么?

主持人注:这可能应该是社区维基。

答案1

这是我的一石二鸟技术。对表格进行排序并markdown 语法无需改变 catcode。

首先创建一个列表和一个辅助宏来添加元素。

\let\alist\@empty

\def\addtolist#1#2{%
  \lst@lAddTo#1{#2}}

创建两个命令,一个基于 A 列(作为主索引)或 B 列进行排序。

\def\RA#1|#2|#3|#4;{%
  \addtolist{\alist}{#1#2,}%
  \expandafter\gdef\csname#1#2\endcsname{\textit{#1}&#2&#3&#4\cr\relax}
  \lst@BubbleSort{\alist}
}

排序宏来自listings文档类lstdoc。数据添加如下,使用分号作为行尾分隔符是我使用 Pascal 时遗留下来的,如果最后一列只是数字或单个单词,则可以使用空格。

\RA Lactarius fallax      | velvety milk cap |edible |potentially risky;  
\RA Lactarius camphoratus | candy cap        |edible |aromatic qualities;

在最小情况下,所有内容都放在一个框中,但使用环境或更复杂的宏同样可以很好地工作。更改\RA\RB根据第二列作为主索引进行排序。

\documentclass{article}
\usepackage{lstdoc,booktabs}
\begin{document}
\makeatletter
\let\alist\@empty

\def\addtolist#1#2{%
  \lst@lAddTo#1{#2}
}

\def\RA#1|#2|#3|#4;{%
  \addtolist{\alist}{#1#2,}%
  \expandafter\gdef\csname#1#2\endcsname{\textit{#1}&#2&#3&#4\cr\relax}
  \lst@BubbleSort{\alist}
}

\def\RB#1|#2|#3|#4;{%
   \addtolist{\alist}{#2#1,}%
   \expandafter\gdef\csname#2#1\endcsname{\textit{#1}&#2&#3&#4\cr\relax}
   \lst@BubbleSort{\alist}
}

%% adding the data now
\RA Lactarius fallax      | velvety milk cap |edible |potentially risky;  
\RA Lactarius camphoratus | candy cap        |edible |aromatic qualities;
\RA Suillus pungens       | slippery Jack    |edible |poor taste;
\RA Lactarius affinis     | kindred milk     |edible |unpalatable;
\RA Calocybe carnea       | pink fairhead    |edible |potentially risky;
\RA Amateta ocreata       | death angel      |inedible |highly poisonous;   

%% typesetting the table
\newsavebox{\tempbox}
\savebox{\tempbox}{
\centering
\begin{tabular}{llll}
  \toprule[1pt]
  Species & Common name & Edibility & Remarks\\
  \midrule
  \@for\i:=\alist \do{\csname\i\endcsname}
  \vspace{-14pt}\\\bottomrule
\end{tabular}
}

\begin{table}
\usebox{\tempbox}
\caption{Some mushrooms from Wikipedia}
\end{table}
\end{document}

您可以添加更多技巧,具体取决于您想要实现的目标,稍微改变的定义,\RA然后\RB您可以创建指向维基百科文章的自动链接或插入图像。这比使用 DBtools 快得多,也灵活得多。

答案2

  1. 一个非常有用的方法是\romannumeral扩展其路径上的所有内容,直到找到一个整数。如果整数为负数,则将其扩展为零。这可用于完全扩展某些内容,如下所示:

    \def\a{\b}\def\b{\c}\def\c{\d}\def\d{1}
    \expandafter\show\romannumeral-`\0\a
    

    这里-`0不是一个完整的数字(它需要一个空格才能变成减去的字符代码0),因此 TeX 会向前看,并在前进过程中扩展标记。代码将显示1。另一方面,\expandafter\show\romannumeral0\a会导致一些意外:经过几次扩展后,\a会产生1,而 TeX 现在看到的是\romannumeral01,它将扩展为i(如果前面有更多数字,则为其他值)。(感谢 egreg 的评论。)

  2. \afterassignment我还喜欢使用和的组合\futurelet来提前读取两个标记。例如,

    \newcommand{\readhead} [2]
      {\afterassignment\@gobble\futurelet#1{#2}}
    

    将设置#1为等于标记列表的第一个标记,然后从输入流中#2删除。#2

  3. 测试给定的标记是否是-、、+数字或其他内容:

    \newcommand{\test}[1]{%
      \ifcase\numexpr1\noexpand#11\relax
            % -
      \or   % other
      \or   % +
      \else % digit
      \fi}
    

    如果目标是测试字符的字符代码(不管类别代码),则替换\noexpand为,假设这不是太疯狂。\string\escapechar

  4. 测试某个字符是否是字母。

    \ifnum\numexpr\uccode`#1/26=3 True\else False\fi
    

    当然,如果有人摆弄大写代码,这就会破坏它。

  5. 测试一个字符是否是数字。

    \ifnum 9<1#1 True\else False\fi
    

答案3

我最喜欢的技巧之一是

\begingroup
<assignments>
\def\x{\endgroup<something>}\x

或其变体。例如(来自 LaTeX 内核)

\begingroup
  \catcode`P=12
  \catcode`T=12
  \lowercase{
    \def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}
  \expandafter\endgroup\x
\def\strip@pt{\expandafter\rem@pt\the}

实际上可以简化为

\begingroup
  \catcode`P=12
  \catcode`T=12
  \lowercase{\endgroup\def\rem@pt#1.#2PT}{#1\ifnum#2>\z@.#2\fi}
\def\strip@pt{\expandafter\rem@pt\the}

需要花点时间思考才能理解其中的原理。Heiko Oberdiek 的软件包中有很多\lowercaseor的用法\uppercase(其中充满了其他巧妙的技巧)。

另一个关于同一主题的变体,是在看过 Danie Els 的回答后添加的。没有必要通过以下方式全局定义活跃期:

\begingroup
  \lccode`\~=`\.
  \lowercase{\endgroup
    \def\unitcenterdot{\mathcode`\.=\string"8000 \def~{\,{\cdot}\,}}}
\protected\def\unit#1{%
    \begingroup\unitcenterdot
        \ensuremath{\mathrm{#1}}%
    \endgroup}
\protected\def\SI#1#2{\ensuremath{#1\,\unit{#2}}}

\string是为了避免出现问题巴别塔可能会激活它)。当\lowercase执行时,我们有定义

\def\unitcenterdot{\mathcode`\.=\string"8000 \def.{\,{\cdot}\,}}}

(但句号处于活动状态)。这样,我们只在 内部定义活动句号的含义\unit。这些命令被定义为强大的:将它们放在其他命令的参数中没有问题,因为没有类别代码更改,但有时\writeTeX 会找到没有定义的活动句号。

答案4

我从 Bruno Le Floch 那里学到并偷来的我最喜欢的技巧之一是\slantbox,正如他在剪切变换一个“盒子”。这名义上将采用一个参数并使用\pdf...魔法,将其向右倾斜(正倾斜)或向左倾斜(负倾斜)到任意程度。

首先,这是 Bruno 为您的序言编写的魔法代码:

\newsavebox{\foobox}
\newcommand{\slantbox}[2][.5]
  {%
    \mbox
      {%
        \sbox{\foobox}{#2}%
        \hskip\wd\foobox
        \pdfsave
        \pdfsetmatrix{1 0 #1 1}%
        \llap{\usebox{\foobox}}%
        \pdfrestore
      }%
  }

现在,只需找到创造性的方法来使用它。看起来很简单,但我已经找到了所以用途广泛,可以在我的许多答案中使用它。对于下面列举的许多答案,我将提供图片。

  1. 为没有倾斜的字体提供倾斜:如何使用 libertine 字体的倾斜变体?

  1. 倾斜字母以使其与相邻的对象一致:萨拉曼卡的胜利标志

  1. 改变字母倾斜度以更好地符合传统/历史期望,例如拉普拉斯变换算子的外观:这个拉普拉斯变换符号在 LaTeX 中可用吗?

  1. 绘制符合斜体文本倾斜度的框:在单词中绘制斜体框作为占位符(围绕单个字母)

  1. 三维透视绘图:a)绘制带阴影的 3D 堆叠正方形,b)我怎样才能像 Don 一样在 LaTeX 中显示 pi?, C)Tikz - 透视字母,旋转书写,d)“星球大战”文字效果和 e)将文本放置在 3D 立方体的表面上

在此处输入图片描述

  1. 模拟左手书写:用左手写字

  1. 任何希腊字体:a)直立希腊字体适合计算机现代和 b)文档标题中的数学模式

  1. 创建涉及倾斜的自定义符号:“#” 和 “ff” 之间的符号

  1. 另一个狡猾的伎俩,完全无关\slantbox,是我开发的一个简单的宏,用于在不使用包的情况下进行冒泡排序,如下答案所示,使用 LaTeX 压缩数字列表

宏本身是

\def\listterminator{9999}% SET TO *ANY* VALUE KNOWN NOT TO BE IN LIST (POSITIVE OR NEGATIVE)
\newcommand\bubblesort[1]{\def\sortedlist{}\sortlist#1,\listterminator,\relax}
\def\sortlist#1,#2,#3\relax{%
  \ifnum#2=\listterminator\relax%
    \edef\sortedlist{\sortedlist#1}%
  \else
    \ifnum#1<#2\relax%
      \edef\sortedlist{\sortedlist#1,}%
      \sortlist#2,#3\relax%
    \else%
      \let\tmp\sortedlist%
      \def\sortedlist{}%
      \expandafter\sortlist\tmp#2,#1,#3\relax%
    \fi%
  \fi%
}

它接受像这样的输入\bubblesort{1,2,11, 7, 4, 3},并在宏中产生排序结果,\sortedlist效果为1,2, 3, 4, 7,11

类似的代码,但修复了上述冒泡排序的两个问题:

  1. 如果列表中有两个值相等,则无限循环。此版本删除了二元组。
  2. ! TeX capacity exceeded, sorry [parameter stack size=...]对于大列表来说已经修复。

\listterminator它还通过将对终止值的检查更改为 来消除对 的需要\ifx\undefined#2

\def\bubblesort#1{\def\sortedlist{}\sortlist#1,\undefined,\relax}
\def\sortlist#1,#2,#3\relax{%
  \ifx\undefined#2%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\edef\sortedlist{\sortedlist#1}}
  {%
    \ifnum#1<#2
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
    \fi
    {\edef\sortedlist{\sortedlist#1,}\sortlist#2,#3\relax}
    {%
      \ifnum#1=#2
        \expandafter\@firstoftwo
      \else
        \expandafter\@secondoftwo
      \fi
      {\sortlist#2,#3\relax}%
      {%
        \let\tmp\sortedlist
        \def\sortedlist{}%
        \expandafter\sortlist\tmp#2,#1,#3\relax
      }%
    }%
  }%
}

相关内容