获取宏参数的第一个和第二个字符

获取宏参数的第一个和第二个字符

我遇到过需要分别提取宏参数的第一个和第二个字符的情况。输入始终是两个字符长,并且始终是非特殊文本。我知道有 Lua 或 Latex3 或其他任何解决方案,但如果可能的话,我希望得到一个使用纯 LaTeX2 的答案,不使用或尽量少使用软件包。

答案1

您可以使用宏参数,这些参数可以用括号组以外的其他东西来分隔。因此,您可以使用一个特殊的标记来停止扫描。然后,您可以拾取所需的参数部分并丢弃其余部分。为了避免输入太短时出现错误,我们在末尾添加了一些虚拟内容。(在这里,我过去{}{}{}只是在末尾添加一些空的内容,但您也可以使用未定义的宏,\zzzextractor#1\invalid\invalid\invalid\stophere如果给定的文本不够长,它会抛出错误。)

\documentclass{article}

\newcommand*{\zzz}[1]{\zzzextractor#1{}{}{}\stophere}
\newcommand*{\zzzextractor}{} % just to make sure we don't overwrite an existing macro
% the real definition comes next
\def\zzzextractor#1#2#3\stophere{%
  first: #1,
  second: #2}

\begin{document}
\zzz{lo}

\zzz{ipsum}

\zzz{}
\end{document}

示例输出

这种方法有相当多的局限性。

  • 对于 pdfLaTeX,这不适用于非 ASCII 字符。
  • 如果您提供宏,\zzz您可能会得到意想不到的结果。

如果你的输入保证只包含两个(ASCII)字符,那么下面的方法也可以工作

\documentclass{article}

\makeatletter
\newcommand*{\zzz}[1]{%
  first: \@firstoftwo#1,
  second: \@secondoftwo#1}
\makeatother

\begin{document}
\zzz{lo}

\zzz{al}
\end{document}

因为\@firstoftwo被定义为接受两个参数并扩展为第一个参数,并且\@secondoftwo被定义为接受两个参数并扩展为第二个参数。如果你没有用括号括住传递#1给这两个宏的参数,它们将只抓取前两个标记作为它们的参数。如果参数#1只包含两个标记,那就这样吧。

答案2

LaTeX 内核已经具有所需的命令。

\documentclass{article}

\makeatletter
\newcommand{\firstof}[1]{\@car#1\@nil}
\newcommand{\secondof}[1]{\expandafter\@car\@cdr#1\@nil\@nil}
\newcommand{\restof}[1]{\expandafter\@cdr\@cdr#1\@nil\@nil}
\makeatother

\begin{document}

\firstof{ab}

\secondof{ab}

\firstof{abcde}

\secondof{abcde}

X\restof{ab}X

X\restof{abcde}X

\end{document}

宏的定义非常简单:

% latex.ltx, line 846:
\def\@car#1#2\@nil{#1}
\def\@cdr#1#2\@nil{#2}

在此处输入图片描述

但是,如果输入的长度少于两个标记,则会产生奇怪的错误。以下是一种更安全的方法expl3

\documentclass{article}
\usepackage{expl3} % not needed with LaTeX April 2020 or later

\ExplSyntaxOn
\cs_new:Npn \firstof #1
 {
  \tl_range:nnn { #1 } { 1 } { 1 } % tokens from 1 to 1
 }
\cs_new:Npn \secondof #1
 {
  \tl_range:nnn { #1 } { 2 } { 2 } % tokens from 2 to 2
 }
\cs_new:Npn \restof #1
 {
  \tl_range:nnn { #1 } { 3 } { -1 } % tokens from 3 to the end
 }
\ExplSyntaxOff

\begin{document}

X\firstof{a}X

X\secondof{a}X

X\restof{a}X

X\firstof{ab}X

X\secondof{ab}X

X\restof{ab}X

X\firstof{abcde}X

X\secondof{abcde}X

X\restof{abcde}X

\end{document}

在此处输入图片描述

泛化,您可以指定要选择的项目,或者(可选)指定起点和终点。如上面的代码所示,负数表示“从末尾开始计数”。该宏完全可扩展,因此可以放在 中\edef

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\extract}{O{#2}mm}
 {
  \tl_range:nnn { #3 } { #1 } { #2 }
 }
\ExplSyntaxOff

\begin{document}

X\extract{1}{a}X

X\extract{2}{a}X

X\extract[3]{-1}{a}X

X\extract{1}{ab}X

X\extract{2}{ab}X

X\extract[3]{-1}{ab}X

X\extract{1}{abcde}X

X\extract{2}{abcde}X

X\extract[3]{-1}{abcde}X

X\extract[2]{4}{abcde}X

X\extract{-1}{abcde}X % the last item

\end{document}

在此处输入图片描述

答案3

我认为此类事物有数百种变体。

\documentclass{article}
\newcommand\mytest[1]{%
\def\pft##1##2;{\def\pftfirstchar{##1}\def\pftsecondchar{##2}}%
\expandafter\pft#1;%
The first character is \textit{\pftfirstchar} end the second character
\textit{\pftsecondchar}.\par}
\begin{document}
\mytest{si} \mytest{no} \mytest{ja} \mytest{na}
\end{document}

在此处输入图片描述

当然还存在更多的故障安全变体和包等等。

答案4

我遇到过需要分别提取宏参数的第一个和第二个字符的情况。输入始终(至少)为两个字符长,并且始终为非特殊文本。

为了完整起见,这里有一个基于 LuaLaTeX 的解决方案。它提供了名为 、 和 的 LaTeX 宏\firstchar\secondchar它们\finalchar的参数可以是任何 utf8 编码的文本字符串 - 甚至可以是一个或多个 LaTeX 宏,这些宏将在返回结果文本字符串的第一个、第二个或最后一个字符之前进行扩展。

在此处输入图片描述

\documentclass{article}
\newcommand\firstchar[1]{\directlua{ tex.sprint( unicode.utf8.sub ("#1",1,1))}}
\newcommand\secondchar[1]{\directlua{tex.sprint( unicode.utf8.sub ("#1",2,2))}}
\newcommand\finalchar[1]{\directlua{ tex.sprint( unicode.utf8.sub ("#1",-1))}}

\begin{document}
\obeylines % just to keep this MWE's code compact
Consider the instruction \verb+\foo{Note}+.
The argument's first character is ``\firstchar{Note}''.
The argument's second character is ``\secondchar{Note}''.
The argument's final character is ``\finalchar{Note}''.  
\medskip
Consider the instruction \verb+\foo{öÄüß}+.
The argument's first character is ``\firstchar{öÄüß}''.
The argument's second character is ``\secondchar{öÄüß}''.
The argument's final character is ``\finalchar{öÄüß}''.
\medskip
\def\a{B} \def\b{az}
Consider the instruction \verb+\bar{\a\b}+, where \verb+\def\a{B}+ and \verb+\def\b{az}+.
The expanded argument's first character is ``\firstchar{\a\b}''.
The expanded's argument's second character is ``\secondchar{\a\b}''.
The expanded's argument's final character is ``\finalchar{\a\b}''.
\end{document}

相关内容