
Me gustaría escribir un comando expandible que agregue una cadena S1 al comienzo de otra cadena S2 si S2 no comienza con S1 para garantizar que mi cadena siempre comience con S1.
Actualmente tengo este código que se basa en el paquete xstring
\NewDocumentCommand\forcebeginwith{m m}{%
\edef\expandedstring{#1}%
\edef\expandedbeginning{#2}%
\IfBeginWith{
\expandedstring % String
}{
\expandedbeginning % Beginning
}{
\expandedstring % String
}{
\expandedbeginning\expandedstring % Beginning + String
}
}
Por ejemplo :
\forcebeginwith{fancycolor}{fancy} % fancycolor
\forcebeginwith{color}{fancy} % fancycolor
Pregunta:Me gustaría convertir este comando en un comando expandible NewExpandableDocumentCommand
, pero no tengo idea de cómo hacerlo (me gustaría que el código resultante funcione en versiones de látex que datan de, digamos, hace 5 años, así que me gustaría evitar los súper recientes comandos/paquetes).
Respuesta1
El comando \forcebeginwith
se define con \NewExpandableDocumentCommand
. La prueba se realiza con \str_if_eq:eeTF
. El comando \forcebeginwith
se puede utilizar en el interior \edef
como en el siguiente ejemplo.
\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}
Respuesta2
Si usas pdflatex
, entonces puedes hacerlo con
\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}
Lo probé hasta TeX Live 2012.
Respuesta3
Usando sólo primitivas TeX, el código debería ser así:
\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
Tenga en cuenta que TeX no funciona con "cadenas", solo hay listas de tokens.
Respuesta4
La siguiente solución basada en LuaLaTeX define una macro de usuario llamada \forcebeginwith
. Debería funcionar con versiones del kernel LaTeX que tienen más de una década de antigüedad, ya que las propiedades de la \directlua
primitiva no han cambiado realmente desde su primera aparición. Porque \directlua
es ampliable, también lo es \forcebeginwith
. Tenga en cuenta que los argumentos de \forcebeginwith
no necesitan estar codificados en ASCII; en cambio, se les permite estar codificados en 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}