有没有办法,但有以下限制:
- 无外部包(即无
substr
) - 无条件(
\ifnum
、\ifdefined
等)
从字符串中选择一个字符?即
\CharAt{2}{ABC}
应该得到 B。或者至少是来自分隔参数的一个单词?即
\WordAt{2}{A B C}
应该产生 B。
数组的大小是固定的,因此下面的方法也可以起作用:
\WordAt{2}{A}{B}{C}
重点是使 LaTeX 简单,因为我正在使用plastex
。
答案1
如果位置编号为 9 或更少,则以下操作有效:
\documentclass{article}
\def\ninthofmany#1#2#3#4#5#6#7#8#9{#9\gobbletorelax}
\def\gobbletorelax#1\relax{}
\def\CharAt#1#2{%
\expandafter\ninthofmany\romannumeral\numexpr(9000-\number#1000)#2\relax}
\begin{document}
\CharAt{3}{abcdefg}
\CharAt{2}{abcdefg}
\CharAt{1}{abcdefg}
\end{document}
\CharAt{3}{abcdefg}
例如,在字符串前面添加 6 个“m”(罗马数字 6000)abcdefg
,然后取出结果中的第 9 个字符。使用相同技巧的迭代,可以根据需要扩展第一个参数的限制,但代价是代码越来越长。
如果我们不需要避免\ifnum
(以及大概其他\if
),那么我们可以用几行代码轻松地解决任意大数的这个难题。
答案2
它只能在搜索字符串的前 8 个字符时才有效,如果字符串只有 9 个字符长,它可以获取第 9 个字符。字符串参数中的空格会被忽略。它还可以解析单词列表,其中第一个参数指定为
{{word1}{word2}{word3}...}
\documentclass{article}
\def\nextchar#1#2#3#4#5#6#7#8#9\relax{%
\def\1{#1}%
\def\2{#2}%
\def\3{#3}%
\def\4{#4}%
\def\5{#5}%
\def\6{#6}%
\def\7{#7}%
\def\8{#8}%
\def\9{#9}%
}
\newcommand\findchar[2]{%
\nextchar#1\relax\relax\relax\relax\relax\relax\relax\relax\relax%
\csname#2\endcsname%
}
\begin{document}
\findchar{abc}{2}
should give a b
\findchar{thisisatest}{7}
gives the same result as
\findchar{this is a test}{7}
\findchar{123456789}{9}
can find the ninth character, since the string is only 9 in length
\findchar{{This}{is}{a}{test}{of}{the}{emergency}{broadcast}{system}}{7}
can be found among word lists too.
\end{document}
答案3
我查看了一些plastex
pdf 文档,但找不到关于什么是可以接受的和什么是不可接受的具体解释。
作为一种修辞练习,这里有一个宏\NthElt {N}{list}
,它返回(可扩展地)列表的第 N 个元素(空格吞噬),该列表可能是扩展为某个字符串的宏,或者是其他一些带括号的东西的列表;必须N
是一个明确的正整数。
我的限制是不使用任何\if
,但由于它已在其他答案中使用,我允许自己使用分隔宏和\romannumeral
。 可以完全删除的使用\romannumeral
;分隔宏是该方法的核心。
这e-TeX
正是\numexpr
至关重要的用法。
\documentclass{article}
\makeatletter
\def\gobble@ {}%
\def\gobble@i #1{}%
\def\gobble@ii #1#2{}%
\def\gobble@iii #1#2#3{}%
\def\gobble@iv #1#2#3#4{}%
\def\gobble@v #1#2#3#4#5{}%
\def\gobble@vi #1#2#3#4#5#6{}%
\def\gobble@vii #1#2#3#4#5#6#7{}%
\def\gobtoundef #1\undef {}%
\def\gobtonine #19{}%
%\def\FirstOfTwo #1#2{#1}% here, LaTeX: just use \@firstoftwo
%\def\ThirdOfThree #1#2#3{#3}% here, LaTeX: just use \@thirdofthree
% EXPANDABLY RECOVERS THE #1th ITEM
% #1 MUST BE AN EXPLICIT POSITIVE INTEGER (not a count or not even a macro)
%
\def\NthElt #1#2%
{%
\romannumeral0\expandafter\NthElta\expandafter {\romannumeral-`0#2}{#1}%
}%
\def\NthElta #1#2%
{%
\NthEltb {#2}#1\undef\undef\undef\undef\undef\undef\undef\undef\UNDEF
}%
\def\NthEltb #1%
{%
\IfMoreThanEight #1\undef\@firstoftwo {\NthEltc}{\NthEltGetIt}%
{#1}%
}%
\def\IfMoreThanEight #1#2%
{%
\gobtoundef #2\PerhapsAtMostEight #1%
}%
\def\PerhapsAtMostEight #1%
{%
\gobtonine #1\gobble@ii 9\@thirdofthree
}%
\def\NthEltc #1#2#3#4#5#6#7#8#9%
{%
\gobtoundef #9\NthEltSilentEnd\undef
\expandafter\NthEltb\expandafter{\the\numexpr #1-8\relax}%
}%
\def\NthEltSilentEnd #1\UNDEF { }% space stops the \romannumeral0
\def\NthEltGetIt #1%
{%
\expandafter\expandafter\expandafter\NthEltFinish
\csname gobble@\romannumeral\numexpr#1-1\endcsname
}%
\def\NthEltFinish #1#2\UNDEF {\gobtoundef #1\expandafter\space
\gobble@iii\undef\space #1}%
% space stops the \romannumeral0
\makeatother
\begin{document}
\NthElt {1}{ABCDEFGHIJKLMNOPQRSTUVWXYZ}
\NthElt {7}{ABCDEFGHIJKLMNOPQRSTUVWXYZ}
\NthElt {26}{ABCDEFGHIJKLMNOPQRSTUVWXYZ}
+++\NthElt {27}{ABCDEFGHIJKLMNOPQRSTUVWXYZ}+++
% 0 is not legal as index, but acts as if 1.
+++\NthElt {0}{ABCDEFGHIJKLMNOPQRSTUVWXYZ}+++
\newcount\cnta
\loop
\advance\cnta 1
\expandafter\NthElt\expandafter{\the\cnta}{ABCDEFGHIJKLMNOPQRSTUVWXYZ}.%
\ifnum\cnta < 30
\repeat
\edef\z {\NthElt
{37}{ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ{THIS IS ME!}LMNOPQRSTUVWXYZ}}
\texttt{\meaning\z}
\end{document}