提取第一个、最后一个和其余的 token

提取第一个、最后一个和其余的 token

这个问题与提取宏参数的第一个和最后一个字符?

看起来,如果除了获取第一个和最后一个令牌之外,还想积累其余的令牌,那么解决方案就不简单了。我的解决方案似乎很复杂。我想知道 David Carlisle 能否立即从口袋里掏出一个更简洁的解决方案。应避免完全展开令牌,因为它们可能包含未定义的控件。

\documentclass{article}
\makeatletter
\usepackage{catoptions}

\def\fl#1{\fl@i#1\@nil\@nil\@nnil}
\def\fl@i#1#2#3\@nnil{%
  \def\rest{}\def\last{}%
  \edef\first{\ifstrcmpTF{#1}\@nil{}{\unexpanded{#1}}}%
  \edef\reserved@b{\unexpanded{#3}}%
  \ifcsemptyTF\reserved@b{%
    \edef\last{\ifstrcmpTF{#2}\@nil{}{\unexpanded{#2}}}%
  }{%
    \ifcseqTF\reserved@b\@nnil{%
      \edef\last{\ifstrcmpTF{#2}\@nil{}{\unexpanded{#2}}}%
    }{%
      \edef\last{\unexpanded{#2}}%
      \fl@ii#3\@nnil
    }%
  }%
  \ifx\last\rest\def\rest{}\fi
}
\def\fl@ii#1#2#3\@nnil{%
  \ifstrcmpTF{#1}\@nil{}{%
    \ifstrcmpTF{#2}\@nil{%
      \edef\rest{\expandcsonce\last\expandcsonce\rest}%
      \edef\last{\unexpanded{#1}}%
    }{%
      \edef\rest{\expandcsonce\rest\unexpanded{#1}}%
      \fl@ii#2#3\@nnil
    }%
  }%
}

\def\x{\string\x}
\def\y#1{\fl{#1}\immediate\write20{Given token
  [\iflacus#1\dolacus empty/null\else#1\fi]
  ^^J[\first][\last][\rest]}
}
\immediate\write20{[first][last][rest]}
\y{}
\y{\x}
\y{1\x2}
\y{123}
\y{1234\x}

\begin{document}
x
\end{document} 

答案1

这是一个解决方案,它所花的时间与标记列表的大小成线性关系,比 egreg 的方法更快。它不保留空格或括号组。

\seq_set_split:Nnn这个想法是使用一个空的“分隔符”参数(在每个标记之间进行分割)将标记列表转换为一个序列,然后使用函数\seq_pop_left:NN\seq_pop_right:NN从序列中提取(并删除)第一个和最后一个项目。最后,该序列保存标记列表的内容,但不包含其第一个和最后一个元素;我们需要转换回标记列表:这是在\edef( \tl_set:Nx) 内完成的,将\unexpanded( \exp_not:n) 应用于序列中的每个项目,以防止在此扩展分配中扩展。

\RequirePackage{expl3,xparse}
\ExplSyntaxOn
\seq_new:N \l_your_seq
\DeclareDocumentCommand{\fl}{m}
  {
    \seq_set_split:Nnn \l_your_seq { } {#1}
    \seq_pop_left:NN \l_your_seq \first
    \seq_pop_right:NN \l_your_seq \last
    \tl_set:Nx \middle { \seq_map_function:NN \l_your_seq \exp_not:n }
  }
\ExplSyntaxOff

答案2

LaTeX3 基础设施可用于此:它提供\tl_range:nnn从令牌列表中抓取令牌的功能。

最后,标记列表变量\l_fl_first_tl\l_fl_last_tl\l_fl_rest_tl将包含所需元素。如果标记列表的长度为 1,则其余元素和最后一个元素为空。

\documentclass[a4paper]{article}

\ExplSyntaxOn
\NewDocumentCommand{\fl}{m}
  {
   \tl_set:Nx \l_fl_first_tl { \tl_range:nnn { #1 } { 1 }  { 1 }  }
   \tl_set:Nx \l_fl_rest_tl  { \tl_range:nnn { #1 } { 2 }  { -2 } }
   \int_compare:nT { \tl_count:n { #1 } > 1 }
    {
     \tl_set:Nx \l_fl_last_tl  { \tl_range:nnn { #1 } { -1 } { -1 } }
    }
   % now show the result as [first] [last] [rest]
   \iow_term:x { === \tl_to_str:n { #1 } === }
   \iow_term:x
    {
     [\tl_to_str:N \l_fl_first_tl]
     [\tl_to_str:N \l_fl_last_tl]
     [\tl_to_str:N \l_fl_rest_tl]
    }
  }
\tl_new:N \l_fl_first_tl
\tl_new:N \l_fl_rest_tl
\tl_new:N \l_fl_last_tl
\ExplSyntaxOff

\def\x{aaaa}
\fl{\x}
\fl{1\x2}
\fl{123}
\fl{1234\x}
\fl{1234{\x\x}}

\stop

结果是

===\x ===
[\x ][][]
===1\x 2===
[1][2][\x ]
===123===
[1][3][2]
===1234\x ===
[1][\x ][234]
===1234{\x \x }===
[1][{\x \x }][234]

答案3

这段代码并不假装是最好的解决方案,但它确实是更短。宏一次读取一个标记的输入。非边缘标记被附加到\middle。处理边缘情况留作练习。然后欢呼\expandafter

\documentclass{article}

\makeatletter
\def\split#1{%
  \def\middle{}%
  \def\last{}%
  \let\next=\split@next
  \split@#1\@@end}
\def\split@#1{%
  \def\first{#1}%
  \split@next}
\def\split@next#1{%
  \ifx#1\@@end
    \let\next=\relax
  \else
    \expandafter\expandafter\expandafter\def
    \expandafter\expandafter\expandafter\middle
    \expandafter\expandafter\expandafter{\expandafter\middle\last}%
    \def\last{#1}%
  \fi
  \next}
\makeatother

\begin{document}

\split{12345}
\first,\middle,\last

\end{document}

答案4

这是一种使用令牌循环的方法。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle}
\def\x{\string\x}
\newcounter{tokcount}
\newcommand\testnext{\stepcounter{tokcount}\tcpeek\zzz}
\def\z#1{\ifx\empty#1\empty[][][]\else
  \setcounter{tokcount}{0}\zz#1\endzz\fi}
\def\zz#1#2\endzz{[#1]\tokcycle
  {\testnext\tctestifx{\empty\zzz}{[##1]}{\addcytoks{##1}}}
  {\testnext\tctestifx{\empty\zzz}{[##1]}{\addcytoks{##1}}}
  {\testnext\tctestifx{\empty\zzz}{[##1]}{\addcytoks{##1}}}
  {\testnext\tctestifx{\empty\zzz}{[##1]}{\addcytoks{##1}}}
  {#2}%
  \ifnum\thetokcount=0 []\fi
  \expandafter[\the\cytoks]%
}
\begin{document}
[First][Last][Mid]

\z{}

\z{\x}

\z{12}

\z{1\x3}

\z{123}

\z{12 }

\z{1 3}

\z{1234\x}

\z{1234{\x\x}}

\z{1234{\x\x}6} Detokenized Mid: \detokenize\expandafter{\the\cytoks}
\end{document}

在此处输入图片描述

相关内容