引数の最初の文字を上付き文字として、最後の 2 文字を下付き文字として出力するコマンドを定義したいと思います。次のように入力します。
\mynewcommand{abcde}
それは同じことをするはずです
\textsuperscript{a}bc\textsubscript{de}
そのようなコマンドを使えば何時間も時間を節約できるのですが、やり方がわかりません
編集: 申し訳ありませんが、おそらく明確に説明していませんでした。真ん中の部分は何でも構いません。したがって、最初の文字だけが上付き文字で、最後の 2 文字は下付き文字になります。
必要なものは次のとおりです:
\anothernewcommand{a some text that can contain \textit{other commands} cd}
同じことをするべきである
\textsuperscript{a} some text that can contain \textit{other commands} \textsubscript{cd}
答え1
のような構文の方が明確だと思います\mynewcommand{a}{bc}{de}
。とにかく、上付き文字の後と下付き文字の前のスペースの扱いが異なる 2 つの実装を提供できます。どちらかをお選びください。
\documentclass{article}
%\usepackage{xparse} % not needed for LaTeX 2020-10-01
\ExplSyntaxOn
\NewDocumentCommand{\mynewcommandA}{m}
{
\textsuperscript{\tl_range:nnn { #1 } { 1 } { 1 } }
\tl_range:nnn { #1 } { 2 } { -3 }
\textsubscript{\tl_range:nnn { #1 } { -2 } { -1 } }
}
\NewDocumentCommand{\mynewcommandB}{m}
{
\tl_set:Nn \l_tmpa_tl { #1 }
\tl_replace_all:Nnn \l_tmpa_tl { ~ } { \c_space_tl }
\textsuperscript{\tl_range:Nnn \l_tmpa_tl { 1 } { 1 } }
\tl_range:Nnn \l_tmpa_tl { 2 } { -3 }
\textsubscript{\tl_range:Nnn \l_tmpa_tl { -2 } { -1 } }
}
\ExplSyntaxOff
\begin{document}
\textbf{Leading and trailing spaces are not kept}
\mynewcommandA{abcde}
\mynewcommandA{a some text that can contain \textit{other commands} cd}
\bigskip
\textbf{Leading and trailing spaces are kept}
\mynewcommandB{abcde}
\mynewcommandB{a some text that can contain \textit{other commands} cd}
\end{document}
さらに詳しい情報。 この関数は\tl_range:nnn
3 つの引数を取ります。最初の引数はテキスト、2 番目と 3 番目は抽出する範囲を指定する整数です。つまり、 は{1}{1}
最初の項目を抽出します ( にすることもできますが、統一性を保つためにより複雑な 関数を使用しました)。一方、 は最後の 2 つの項目を指定します (負のインデックスでは、最後から抽出が開始されます)。\tl_head:n
は、右から 2 番目の項目から 3 番目の項目までの範囲を指定します。{-2}{-1}
{2}{-3}
ただし、抽出された部分の境界にスペースを残すには、まずスペースを に置き換える必要があります\c_space_tl
。これはスペースに拡張されますが、抽出関数によってトリミングされません。 の構文は\tl_set:Nnn
同じですが、最初の引数のみが tl 変数である必要があります。
答え2
複雑さを考慮して、この問題を TeX プリミティブ レベルで解決する方法を示します。
\newcount\bufflen
\def\splitbuff #1#2{% #1: number of tokens from end, #2 data
% result: \buff, \restbuff
\edef\buff{\detokenize{#2} }%
\edef\buff{\expandafter}\expandafter\protectspaces \buff \\
\bufflen=0 \expandafter\setbufflen\buff\end
\advance\bufflen by-#1\relax
\ifnum\bufflen<0 \errmessage{#1>buffer length}\fi
\ifnum\bufflen>0 \edef\buff{\expandafter}\expandafter\splitbuffA \buff\end
\else \let\restbuff=\buff \def\buff{}\fi
\edef\tmp{\gdef\noexpand\buff{\buff}\gdef\noexpand\restbuff{\restbuff}}%
{\endlinechar=-1 \scantokens\expandafter{\tmp}}%
}
\def\protectspaces #1 #2 {\addto\buff{#1}%
\ifx\\#2\else \addto\buff{{ }}\afterfi \protectspaces #2 \fi}
\def\afterfi #1\fi{\fi#1}
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\setbufflen #1{%
\ifx\end#1\else \advance\bufflen by1 \expandafter\setbufflen\fi}
\def\splitbuffA #1{\addto\buff{#1}\advance\bufflen by-1
\ifnum\bufflen>0 \expandafter\splitbuffA
\else \expandafter\splitbuffB \fi
}
\def\splitbuffB #1\end{\def\restbuff{#1}}
% --------------- \mynewcommand implementation:
\def\textup#1{$^{\rm #1}$} \def\textdown#1{$_{\rm #1}$}
\def\mynewcommand#1{\mynewcommandA#1\end}
\def\mynewcommandA#1#2\end{%
\textup{#1}\splitbuff 2{#2}\buff \textdown{\restbuff}}
% --------------- test:
\mynewcommand{abcde}
\mynewcommand{a some text that can contain {\it other commands} cd}
\bye
答え3
多様性のために、LuaLaTeX ベースのソリューションを示します。これは、Lua の文字列関数とを使用してstring.sub
タスクstring.len
を実行する Lua 関数を設定します。また、 と呼ばれる LaTeX「ラッパー」マクロも設定します\mynewcommand
。このマクロは、引数を Lua 関数に渡す前に 1 回展開します。
このソリューションでは、Luaの文字列関数のバリエーションとを使用してunicode.utf8.sub
、unicode.utf8.len
引数に\mynewcommand
UTF8でエンコードされた任意の有効な文字列を指定できます。(もちろん、印刷文字列内の文字を表示するには、適切なフォントをロードする必要があります。 の引数には、\mynewcommand
プリミティブとマクロを含めることができます。
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode} % for "\luaexec" and "\luastringO" macros
\luaexec{
% Define a Lua function called "mycommand"
function mycommand ( s )
local s1,s2,s3
s1 = unicode.utf8.sub ( s, 1, 1 )
s2 = unicode.utf8.sub ( s, 2, unicode.utf8.len(s)-2 )
s3 = unicode.utf8.sub ( s, -2 )
return ( "\\textsuperscript{" ..s1.. "}" ..s2.. "\\textsubscript{" ..s3.. "}" )
end
}
% Create a wrapper macro for the Lua function
\newcommand\mynewcommand[1]{\directlua{tex.sprint(mycommand(\luastringO{#1}))}}
\begin{document}
abcde $\to$ \mynewcommand{abcde}
öçäßüéà $\to$ \mynewcommand{öçäßüéà}
\mynewcommand{a some text that can contain \textit{\textbf{other commands}} cd}
\end{document}