
Eu gostaria de escrever um comando expansível que adicione uma string S1 no início de outra string S2 se S2 não começar com S1, para garantir que minha string sempre comece com S1.
Atualmente tenho este código que depende do pacote xstring
\NewDocumentCommand\forcebeginwith{m m}{%
\edef\expandedstring{#1}%
\edef\expandedbeginning{#2}%
\IfBeginWith{
\expandedstring % String
}{
\expandedbeginning % Beginning
}{
\expandedstring % String
}{
\expandedbeginning\expandedstring % Beginning + String
}
}
Por exemplo :
\forcebeginwith{fancycolor}{fancy} % fancycolor
\forcebeginwith{color}{fancy} % fancycolor
Pergunta:Eu gostaria de converter este comando em um comando expansível NewExpandableDocumentCommand
, mas não tenho ideia de como fazer isso (gostaria que o código resultante funcionasse em versões de látex datadas de, digamos, 5 anos atrás, então gostaria de evitar super duper recente comandos/pacotes).
Responder1
O comando \forcebeginwith
é definido com \NewExpandableDocumentCommand
. O teste é realizado com \str_if_eq:eeTF
. O comando \forcebeginwith
pode ser usado internamente \edef
como no exemplo abaixo.
\documentclass[border=6pt,varwidth]{standalone}
\ExplSyntaxOn
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
{
\str_if_eq:eeTF {#2} { \str_range:nnn {#1} { 1 } { \str_count:n {#2} } }
{#1}
{ #2#1 }
}
\ExplSyntaxOff
\begin{document}
\forcebeginwith{fancycolor}{fancy}\\% fancycolor
\forcebeginwith{color}{fancy}\\% fancycolor
\edef\testA{\forcebeginwith{LaTeX}{La}}\testA\\
\edef\testB{\forcebeginwith{TeX}{La}}\testB
\end{document}
Responder2
Se você usar pdflatex
, então você pode fazer isso com
\documentclass{article}
\newcommand{\forcebeginwith}[2]{%
\ifnum\pdfmatch{^#2}{#1}=0 #2\fi#1%
}
\begin{document}
\forcebeginwith{fancycolor}{fancy}% fancycolor
\forcebeginwith{color}{fancy}% fancycolor
\edef\testA{\forcebeginwith{LaTeX}{La}}\testA
\edef\testB{\forcebeginwith{TeX}{La}}\testB
\end{document}
Eu testei até o TeX Live 2012.
Responder3
Usando apenas primitivas TeX, o código deve ficar assim:
\def\forcebeginwith#1#2{\fbwA .#1\end .#2\end{#1}{#2}}
\def\fbwA #1#2\end #3#4\end #5#6{%
\ifx #1#3%
\ifx \end#4\end #5% S2 is included at the start of S1, print S1 only
\else
\ifx \end#2\end {#5} shorter than {#6}, something wrong%
\else \fbwB {#2\end #4\end {#5}{#6}}%
\fi
\fi
\else #6#5% S2 isn't inluded at the start of S1, print S2S1.
\fi
}
\def\fbwB #1\fi\fi#2\fi{\fi\fi\fi \fbwA #1}
% test:
\message{\forcebeginwith{fancycolor}{fancy}}
\message{\forcebeginwith{color}{fancy}}
\bye
Observe que o TeX não funciona com "strings", existem apenas listas de tokens.
Responder4
A seguir, a solução baseada em LuaLaTeX define uma macro de usuário chamada \forcebeginwith
. Ele deve funcionar com versões do kernel LaTeX com mais de uma década, já que as propriedades do \directlua
primitivo não mudaram realmente desde sua primeira aparição. Porque \directlua
é expansível, então é \forcebeginwith
. Observe que os argumentos de \forcebeginwith
não precisam ser codificados em ASCII; em vez disso, eles podem ser codificados em UTF8.
% !TEX program = lualatex
\documentclass{article} % or some other suitable document class
\directlua{% Define the Lua function 'forcebeginwith':
function forcebeginwith ( s1 , s2 )
if unicode.utf8.sub ( s1 , 1 , unicode.utf8.len ( s2 ) ) == s2 then
return ( s1 )
else
return ( s2..s1 )
end
end
}
\newcommand\forcebeginwith[2]{%
\directlua{ tex.sprint ( forcebeginwith ( "#1" , "#2" ) ) }}
\newcommand\Za{color}
\newcommand\Zb{fancy}
\begin{document}
\obeylines % just for this document
\forcebeginwith{fancycolor}{fancy}
\forcebeginwith{color}{fancy}
\smallskip
% Demonstrate that '\forcebeginwith' is expandable
\forcebeginwith{\Zb\Za}{\Zb}
\forcebeginwith{\Za}{\Zb}
\end{document}