提取宏参数的第一个和最后一个字符?

提取宏参数的第一个和最后一个字符?

在 LaTeX 中,如何提取/隔离/确定宏参数的第一个和最后一个字符?

具体来说,在我处理的情况下,参数恰好是一个十进制整数(称为 N)。我能想到的一种方法是计算最右边的数字 N mod 10,最左边的数字重复除以 10——但我还没有尝试过这样的事情,我不知道这有多合理,甚至不知道在 (La)TeX 中是否可行。将字符提取为字符串实体也可以;我没有生成数值的要求。(编辑:我忘了之前提到,我更希望解决方案适用于任意大的数值——或者至少最多 7 位或 10 位数字——这可能需要基于字符串的解决方案而不是数字解决方案。)

最终,我只需要能够使用 if/then 构造进行比较的形式的孤立字符,例如:

\newcommand{\foo}[2]{%
  (something to extract rightmost digit of #1)
  (something to extract leftmost digit of #2)
  ...
  \ifthenelse{\rightmost\equal 2}{\kern.02em}{}%
  \ifthenelse{\rightmost\equal 4}{\kern.03em}{}%
  \ifthenelse{\rightmost\equal 7}{\kern-.02em}{}%
  ...
  \ifthenelse{\leftmost\equal 1}{\kern.02em}{}%
  \ifthenelse{\leftmost\equal 4}{\kern-.03em}{}%
  \ifthenelse{\leftmost\equal 5}{\kern.03em}{}%
  \ifthenelse{\leftmost\equal 7}{\kern.03em}{}%
  ...
}

其他背景:这是为了微调分数分子和分母的字距(相关问题改善分数的字距调整)。

答案1

您可以使用xstring包裹

\documentclass{article}

\usepackage{xstring}

\newcommand{\mymacro}[1]{%
    \StrLeft{#1}{1}[\firstletter]%
    \StrRight{#1}{1}[\lastletter]%
    First letter: \firstletter

    Last letter: \lastletter
}

\begin{document}
    \mymacro{ABCDEF}
\end{document}

我有点忙所以请原谅我没有在你的 MWE 中构建它;-)

答案2

或者在经典 TeX 中;以下定义\fst\lst为第一个和最后一个字符(或为空以进行简短输入)

\def\fl#1{\flx#1\empty\empty\empty}
\def\flx#1#2#3\empty{%
\edef\fst{#1}%
 \edef\cdar{#2}%
 \edef\cddr{#3}%
  \ifx\cddr\empty
    \let\lst\cdar
  \else
     \expandafter\flxx
   \fi
  #3}
\def\flxx#1#2\empty{%
 \edef\car{#1}%
  \ifx\car\empty
  \else
     \let\lst\car
     \expandafter\flxx
   \fi
  #2\empty}

\immediate\write20{===}
\fl{}\immediate\write20{[\fst][\lst]}
\immediate\write20{===1}
\fl{1}\immediate\write20{[\fst][\lst]}
\immediate\write20{===12}
\fl{12}\immediate\write20{[\fst][\lst]}
\immediate\write20{===123}
\fl{123}\immediate\write20{[\fst][\lst]}
\immediate\write20{===1234}
\fl{1234}\immediate\write20{[\fst][\lst]}

\end



===
[][]
===1
[1][]
===12
[1][2]
===123
[1][3]
===1234
[1][4]

答案3

根据您的要求,这里有 3 种解决方案expl3。为了执行测试,我会使用\prg_case_int:nnn而不是一组临时的\ifthenelse语句:那些比较慢。

(1)最简单的方法是使用\tl_head:n{#1}来访问数字的第一位数字,然后\int_mod:nn {#1}{10}访问最后一位数字。这适用于小于 2^{31} 的数字,以及大约 2011 年 6 月以后的 expl3 版本。

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\newcommand {\foo} [2] {
  \prg_case_int:nnn { \int_mod:nn {#1} {10} }
    {
      {1} { \kern .02em \relax }
      {4} { \kern .03em \relax }
      {7} { \kern -.02em \relax }
    }
    { }
  \prg_case_int:nnn { \tl_head:n {#2} }
    {
      {1} { \kern .02em \relax }
      {4} { \kern -.03em \relax }
      {5} { \kern .03em \relax }
      {7} { \kern .03em \relax }
    }
    { }
}
\ExplSyntaxOff

(2) 对于最新版本expl3(2012 年 1 月中旬以后),使用\tl_item:nn可能是最好的,因为它适用于任何整数,而且您可能并不真正想强制要求分子和分母是整数。Namnely\tl_item:nn {#1} {<integer>}给出<integer>标记列表中的第 - 个标记,从最左边的标记(第一个数字)的零开始,负索引从最右边的标记的 -1 开始。特别是,

\tl_item:nn { abcd } { 0 } % => a, left-most token
\tl_item:nn { abcd } { 2 } % => c
\tl_item:nn { abcd } { -1 } % => d, right-most token
\tl_item:nn { abcd } { -5 } % => nothing: index out of bounds.

(3)如果你需要一个既适用于任意长整数又适用于旧版本的解决方案,那么你可以将从到 的expl3行替换为\newcommand\prg_case_int:nnn { \int_mod:nn {#1} {10} }

%----->8---- cut here
\tl_new:N \l_foo_tl
\newcommand {\foo} [2] {
  \tl_clear:N \l_foo_tl
  \tl_map_inline:nn {#1} { \tl_set:Nn \l_foo_tl {##1} }
  \prg_case_int:nnn { \l_foo_tl }
%-----8<---- cut here

这个想法是,我遍历字符串并将每个字符存储在 中\l_foo_tl,直到到达字符串末尾。因此,最后一个字符仍保留在 中\l_foo_tl。这是\int_mod:nn {#1} {10}获取最后一位数字的一个很好的替代方案。但是,我上面给出的另外两个解决方案从长远来看更好(尤其是\tl_item:nn一个)。

相关内容