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}
Mais algumas informações. A função \tl_range:nnn
leva 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.sub
e string.len
realiza 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.sub
e unicode.utf8.len
, para permitir que o argumento de \mynewcommand
seja qualquer string válida de caracteres codificados em utf8. (Claro, paraimprimiros caracteres na string, uma fonte adequada deve ser carregada.) O argumento de \mynewcommand
pode conter primitivas e macros.
% !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}