假设我有一个宏
\def\x{This is a string 2015/12.}
我想要一个宏\extract{string}{number}
,它仅使用原始宏返回字符串中位置编号处的字符。我查看了该xstring
包,但对纯原始解决方案感兴趣。这应该很简单,但我很难弄清楚。我认为它应该与 expand 一起使用。
答案1
假设您的字符串仅包含可打印的 ASCII 字符,这是一个相当笨拙的实现。最后一个例子表明,括号组被视为单个项目。
\catcode`@=11
\def\extract{\futurelet\next\extract@save}
\def\extract@save{%
\ifx\next[%
\expandafter\extract@save@opt
\else
\let\extract@return\@firstofone
\expandafter\extract@
\fi
}
\def\extract@save@opt[#1]{%
\def\extract@return##1{\def#1{##1}}%
\extract@
}
\def\extract@#1#2{%
\edef\extract@string{#1}%
\extract@loop=\z@
\extract@max=#2\relax
\expandafter\extract@i\extract@string\extract
}
\def\extract@i{%
\advance\extract@loop\@ne
\futurelet\next\extract@ii
}
\def\extract@ii{%
\ifx\next\extract
\expandafter\@gobble
\else
\expandafter\extract@iii
\fi}
\def\extract@iii{%
\ifx\next\space@token
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\extract@check@space}%
{\extract@check}%
}
\def\extract@check@space{%
\ifnum\extract@loop=\extract@max
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\extract@return{ }\extract@finish}%
{\expandafter\extract@i\@firstofone}%
}
\def\extract@check#1{%
\ifnum\extract@loop=\extract@max
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\extract@return{#1}\extract@finish}%
{\extract@i}%
}
\def\extract@finish#1\extract{}
\newcount\extract@loop
\newcount\extract@max
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
\long\def\@firstofone#1{#1}
\long\def\@gobble#1{}
\begingroup\def\\ \\{\endgroup\let\space@token= }\\ \\
\catcode`@=12
X\extract{abc def}{3}X (should be c)
X\extract{abc def}{4}X (should be space)
X\extract{abc def}{5}X (should be d)
X\extract{abc def}{8}X (should be empty)
X\extract{abc }{4}X (should be space)
\def\mystring{abc def}
X\extract\mystring{7}X (should be f)
\extract[\foo]\mystring{6}
{\tt\meaning\foo}
\extract[\foo]{A{BC}D}{2}
{\tt\meaning\foo}
\bye
如果没有可选参数,则该项目仅在输入流中返回;如果有可选参数,则它将保存在括号内给出的控制序列中。
当然,我会用完全不同的方法。使用此代码,\extract
可以完全扩展,如最后的示例所示\edef
。请注意,您也可以向后计数。该代码需要 e-TeX 引擎,因此不需要 Knuth TeX。
\input expl3-generic
\ExplSyntaxOn
\cs_new:Npn \extract #1 #2
{
\str_item:fn { #1 } { #2 }
}
\cs_generate_variant:Nn \str_item:nn {f}
\ExplSyntaxOff
X\extract{abc def}{3}X (should be c)
X\extract{abc def}{4}X (should be space)
X\extract{abc def}{5}X (should be d)
X\extract{abc def}{8}X (should be empty)
X\extract{abc }{4}X (should be space)
\def\mystring{abc def}
X\extract\mystring{7}X (should be f)
X\extract\mystring{-2}X (should be e)
\edef\foo{\extract\mystring{6}}
{\tt\meaning\foo}
\bye
答案2
类似这样的?显示忽略和计数空格。为 pdftex 设置,但带有 pdflatex 的注释行。
%\documentclass{article}
\def\extract{\catcode`\ =\active\extractx}
\def\extractx#1#2{\def\extractcount{#2}\expandafter\extracthelp#1\relax}
\def\extracthelp#1#2\relax{%
\edef\extractcount{\the\numexpr\extractcount-1\relax}%
\ifnum\extractcount=0\relax``#1''\else%
\ifx\relax#2\relax[EOF]\else\extracthelp#2\relax\fi\fi%
}
%\begin{document}
Spaces ignored: \def\x{This is a string 2015/12.}
\extract{\x}{1}
\extract{\x}{5}
\extract{\x}{6}
\extract{\x}{22}
Spaces counted: {\catcode`\ =\active \gdef\x{This is a string 2015/12.}}
\extract{\x}{1}
\extract{\x}{5}
\extract{\x}{6}
\extract{\x}{22}
%\end{document}
\bye