在 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
一个)。