Extract a character at position x from a string using primitives
Something like this? Shown both with ignoring and with counting spaces. Set up for pdftex, but with commented lines for 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
Assuming your string only contains printable ASCII characters, here's a quite clumsy implementation. The last example shows that braced groups are treated as single items.
\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
Without the optional argument, the item is just returned in the input stream; with the optional argument it is saved in the control sequence given between brackets.
Of course I'd do it quite differently. With this code, \extract
is fully expandable as shown with the final \edef
example. Note that you can also count backwards. The code requires an e-TeX engine, so not 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