Um comando expansível que adiciona uma string a um argumento se a string estiver faltando

Um comando expansível que adiciona uma string a um argumento se a string estiver faltando

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 \forcebeginwithpode ser usado internamente \edefcomo no exemplo abaixo.

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

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 \directluaprimitivo não mudaram realmente desde sua primeira aparição. Porque \directluaé expansível, então é \forcebeginwith. Observe que os argumentos de \forcebeginwithnão precisam ser codificados em ASCII; em vez disso, eles podem ser codificados em UTF8.

insira a descrição da imagem aqui

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

informação relacionada