Subíndices y superíndices automatizados

Subíndices y superíndices automatizados

Me gustaría definir un comando que imprima la primera letra de su argumento como superíndice y las dos últimas letras como subscripción. Entonces si escribo:

\mynewcommand{abcde}

debería hacer lo mismo que

\textsuperscript{a}bc\textsubscript{de}

un comando así me ahorraría horas de tiempo, pero no sé cómo hacerlo

Editar: Lo siento, probablemente no lo tuve claro, la parte del medio puede serlo todo. Así que sólo la primera letra debe ser un superíndice y las dos últimas un subíndice.

Lo que necesito es:

\anothernewcommand{a some text that can contain \textit{other commands} cd}

que debería hacer lo mismo que

\textsuperscript{a} some text that can contain \textit{other commands} \textsubscript{cd}

Respuesta1

Creo que una sintaxis como \mynewcommand{a}{bc}{de}sería más clara. De todos modos, puedo ofrecer dos implementaciones que se diferencian en el tratamiento de los espacios después del superíndice y antes del subíndice. Elige tu opción.

\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}

ingrese la descripción de la imagen aquí

Más información. La función \tl_range:nnntoma tres argumentos donde el primero es texto, el segundo y el tercero son números enteros que especifican el rango a extraer; so {1}{1}extrae el primer elemento (también puede ser \tl_head:n, pero usé la función más compleja para uniformidad), mientras que {-2}{-1}especifica los dos últimos elementos (con índices negativos la extracción comienza desde el final); {2}{-3}especifica el rango desde el segundo elemento hasta el tercero comenzando desde la derecha.

Sin embargo, para mantener espacios en los límites de las partes extraídas, primero debemos reemplazar los espacios con \c_space_tl, que se expandirá a un espacio, pero las funciones de extracción no lo recortarán. La sintaxis de \tl_set:Nnnes la misma, sólo que el primer argumento tiene que ser una variable tl.

Respuesta2

En aras de la complejidad, muestro cómo resolver este problema en el nivel primitivo de 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

Respuesta3

En aras de la variedad, aquí tienes una solución basada en LuaLaTeX. Configura una función de Lua que, a su vez, utiliza las funciones de cadena de Lua string.suby string.lenrealiza su tarea. También configura una macro "contenedor" de LaTeX llamada \mynewcommand, que expande su argumento una vez antes de pasarlo a la función Lua.

La solución en realidad emplea variantes de las funciones de cadena de Lua unicode.utf8.suby unicode.utf8.len, para permitir que el argumento de \mynewcommandsea cualquier cadena válida de caracteres codificados en utf8. (Por supuesto, paraimprimirlos caracteres de la cadena, se debe cargar una fuente adecuada). El argumento de \mynewcommandpuede contener primitivas y macros.

ingrese la descripción de la imagen aquí

% !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}

información relacionada