Sub e sobrescritos automatizados

Sub e sobrescritos automatizados

Gostaria de definir um comando que imprima a primeira letra do seu argumento como sobrescrito e as duas últimas letras como subscrito. Então, se eu digitar:

\mynewcommand{abcde}

deveria fazer o mesmo que

\textsuperscript{a}bc\textsubscript{de}

tal comando me pouparia horas de tempo, mas não sei como fazê-lo

Editar: Desculpe, provavelmente não fui claro, a parte do meio pode ser tudo. Portanto, apenas a primeira letra deve ser sobrescrita e as duas últimas, subscrita.

O que eu preciso é:

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

que deveria fazer o mesmo que

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

Responder1

Acredito que uma sintaxe como essa \mynewcommand{a}{bc}{de}seria mais clara. De qualquer forma, posso oferecer duas implementações que diferem no tratamento dos espaços após o sobrescrito e antes do subscrito. Faça sua escolha.

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

insira a descrição da imagem aqui

Mais algumas informações. A função \tl_range:nnnleva três argumentos onde o primeiro é algum texto, o segundo e o terceiro são inteiros que especificam o intervalo a ser extraído; so {1}{1}extrai o primeiro item (também pode ser \tl_head:n, mas usei a função mais complexa para uniformidade), enquanto {-2}{-1}especifica os dois últimos itens (com índices negativos a extração começa no final); {2}{-3}especifica o intervalo do segundo ao terceiro item, começando da direita.

No entanto, para manter os espaços nos limites das partes extraídas, temos que primeiro substituir os espaços por \c_space_tl, que se expandirá para um espaço, mas não será cortado pelas funções de extração. A sintaxe de \tl_set:Nnné a mesma, apenas o primeiro argumento deve ser uma variável tl.

Responder2

Por uma questão de complexidade, mostro como resolver este problema no nível primitivo do 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

Responder3

Para variar, aqui está uma solução baseada em LuaLaTeX. Ele configura uma função Lua que, por sua vez, faz uso das funções string de Lua string.sube string.lenrealiza sua tarefa. Ele também configura uma macro "wrapper" LaTeX chamada \mynewcommand, que expande seu argumento uma vez antes de passá-lo para a função Lua.

A solução, na verdade, emprega variantes das funções de string Lua, unicode.utf8.sube unicode.utf8.len, para permitir que o argumento de \mynewcommandseja qualquer string válida de caracteres codificados em utf8. (Claro, paraimprimiros caracteres na string, uma fonte adequada deve ser carregada.) O argumento de \mynewcommandpode conter primitivas e macros.

insira a descrição da imagem aqui

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

informação relacionada