Como posso alterar uma frase com base na entrada de um comando?

Como posso alterar uma frase com base na entrada de um comando?

Estou escrevendo um relatório que inclui imagens de enzimas como esta:

insira a descrição da imagem aqui

Gostaria \captionde incluir um guia de cores para que os principais componentes/átomos possam ser descritos em cores (este relatório não está sendo publicado, portanto, com relação ao daltonismo, isso não é um problema). Atualmente estou usando um comando como este:

\newcommand\ColourGuide{%
Colour code: \textcolor{violet}{metal ion}, \textcolor{Green3}{residue}, \textcolor{teal}{ligand}, \textcolor{Yellow3}{substrate}, \textcolor{DarkOrange1}{phosphorus}, \textcolor{red}{oxygen} and \textcolor{RoyalBlue4}{nitrogen}%
}

No entanto, em algumas imagens nem todos os componentes coloridos estão presentes, por isso não seria bom incluir códigos de cores redundantes. Como posso criar uma frase com base na entrada? Por exemplo:

\ColourGuide{M}{R}{S}{O}{N}

produziria:

Código de cores: íon metálico, resíduo, substrato, oxigênio e nitrogênio.

nas cores especificadas. Estou usando lualatexe olhei usando lua(o que seria legal), mas não sei como interagir os dois de maneira adequada (nem eficiente), como os argumentos poderiam ser extraídos, por exemplo, como em Python com input[0]? Eu apreciaria qualquer conselho ou solução através de qualquer método, mas luaseria bom para que eu pudesse começar a aprendê-lo e aplicá-lo a outros comandos que uso lualatexcom frequência.

MWE:

\documentclass{book}

\usepackage[x11names]{xcolor}

\newcommand\ColourGuide{%
Colour code: \textcolor{violet}{metal ion}, \textcolor{Green3}{residue}, \textcolor{teal}{ligand}, \textcolor{Yellow3}{substrate}, \textcolor{DarkOrange1}{phosphorus}, \textcolor{red}{oxygen} and \textcolor{RoyalBlue4}{nitrogen}%
}

\begin{document}

\ColourGuide{}

\end{document}

Como parece:

insira a descrição da imagem aqui

(Não tenho certeza de quais tags colocar nisso)

Responder1

Boa tentativa na sua resposta, mas…

\documentclass{book}

\usepackage[x11names]{xcolor}

\ExplSyntaxOn

\NewDocumentCommand{\ColourGuide}{m}
 {
  Color~code:~\jamest_colourguide:n { #1 }
 }

\seq_new:N \l__jamest_colourguide_seq

\cs_new_protected:Nn \jamest_colourguide:n
 {
  \seq_clear:N \l__jamest_colourguide_seq
  \tl_map_function:nN { #1 } \__jamest_colourguide_add:n
  \seq_use:Nnnn \l__jamest_colourguide_seq { ~and~ } { ,~ } { ~and~}
 }

\cs_new_protected:Nn \__jamest_colourguide_add:n
 {
  \seq_put_right:Nx \l__jamest_colourguide_seq
   {
    \str_case:nn { #1 }
     {
      {a}{\textcolor{red}{oxygen},~\textcolor{DarkOrange1}{phosphorus},~
          \textcolor{Yellow3}{substrate},~\textcolor{Green3}{residue},~
          \textcolor{RoyalBlue4}{nitrogen},~\textcolor{teal}{ligand}~
          and~\textcolor{violet}{metal~ion}.}
      {M}{\textcolor{violet}{metal~ion}}
      {R}{\textcolor{Green3}{residue}}
      {S}{\textcolor{Yellow3}{substrate}}
      {O}{\textcolor{red}{oxygen}}
      {N}{\textcolor{RoyalBlue4}{nitrogen}}
      {L}{\textcolor{teal}{ligand}}
      {P}{\textcolor{DarkOrange1}{phosphorus}}
     }
   }
 }

\ExplSyntaxOff

\begin{document}

\noindent\ColourGuide{MRSON}

\noindent\ColourGuide{LPON}

\noindent\ColourGuide{a}

\end{document}

insira a descrição da imagem aqui

Nenhuma contagem é necessária: o argumento é mapeado caractere por caractere e o código relevante é adicionado à sequência que pode ser usada posteriormente com os separadores adequados.

Talvez seja melhor, para evitar duplicação de código, deixar o argumento vazio se quiser a lista completa.

\documentclass{book}

\usepackage[x11names]{xcolor}

\ExplSyntaxOn

\NewDocumentCommand{\ColourGuide}{m}
 {
  Color~code:~
  \jamest_colourguide:n { #1 }
 }

\seq_new:N \l__jamest_colourguide_seq

\cs_new_protected:Nn \jamest_colourguide:n
 {
  \tl_if_empty:nTF { #1 }
   {
    \jamest_colourguide:n { OPSRNLM }
   }
   {
    \seq_clear:N \l__jamest_colourguide_seq
    \tl_map_function:nN { #1 } \__jamest_colourguide_add:n
    \seq_use:Nnnn \l__jamest_colourguide_seq { ~and~ } { ,~ } { ~and~}
   }
 }

\cs_new_protected:Nn \__jamest_colourguide_add:n
 {
  \seq_put_right:Nx \l__jamest_colourguide_seq
   {
    \str_case:nn { #1 }
     {
      {M}{\textcolor{violet}{metal~ion}}
      {R}{\textcolor{Green3}{residue}}
      {S}{\textcolor{Yellow3}{substrate}}
      {O}{\textcolor{red}{oxygen}}
      {N}{\textcolor{RoyalBlue4}{nitrogen}}
      {L}{\textcolor{teal}{ligand}}
      {P}{\textcolor{DarkOrange1}{phosphorus}}
     }
   }
 }

\ExplSyntaxOff

\begin{document}

\noindent\ColourGuide{MRSON}

\noindent\ColourGuide{LPON}

\noindent\ColourGuide{}

\end{document}

A saída é a mesma.

Responder2

Graças aos comentários, consegui montar uma solução que não é bonita, mas funciona conforme necessário. Adicionando uma resposta de @egreg acomo determinar o número de caracteres no argumento de um comandoe a resposta vinculada @John Kormylocomentoudá isso:

insira a descrição da imagem aqui

\documentclass{book}

\usepackage[x11names]{xcolor}
\usepackage{xstring}

\usepackage{xparse} % loads expl3

\ExplSyntaxOn

\newcounter{Chars}
\newcounter{CharsConstant}

\def\CharsCount#1{%
    \setcounter{Chars}{\tl_count:n { #1 }}%
    \setcounter{CharsConstant}{\tl_count:n { #1 }}%
}

\NewDocumentCommand{\punctOrAnd}{mm}
    {
    \int_compare:nTF { #1 > 1 }
    {
    \int_compare:nTF { #1 = \value{CharsConstant} }
        {
            #2
            }
            {
            ,~#2
            }
    }
    {
    \space and~#2.
    }
 }

\def\ColourGuide#1{\CharsCount{#1}Colour~code:~\scanA#1\end}
\def\scanA#1{%
    \ifx\end#1\else
        \IfStrEq{#1}{a}{\textcolor{red}{oxygen},~\textcolor{DarkOrange1}{phosphorus},~\textcolor{Yellow3}{substrate},~\textcolor{Green3}{residue},~\textcolor{RoyalBlue4}{nitrogen},~\textcolor{teal}{ligand}~and~\textcolor{violet}{metal~ion}.}{}%
        %
        \IfStrEq{#1}{M}{\punctOrAnd{\value{Chars}}{\textcolor{violet}{metal~ion}}}{}%
        \IfStrEq{#1}{R}{\punctOrAnd{\value{Chars}}{\textcolor{Green3}{residue}}}{}%
        \IfStrEq{#1}{S}{\punctOrAnd{\value{Chars}}{\textcolor{Yellow3}{substrate}}}{}%
        \IfStrEq{#1}{O}{\punctOrAnd{\value{Chars}}{\textcolor{red}{oxygen}}}{}%
        \IfStrEq{#1}{N}{\punctOrAnd{\value{Chars}}{\textcolor{RoyalBlue4}{nitrogen}}}{}%
        \IfStrEq{#1}{L}{\punctOrAnd{\value{Chars}}{\textcolor{teal}{ligand}}}{}%
        \IfStrEq{#1}{P}{\punctOrAnd{\value{Chars}}{\textcolor{DarkOrange1}{phosphorus}}}{}%
        %
        \addtocounter{Chars}{-1}%
    \expandafter \scanA \fi
}

\ExplSyntaxOff

\begin{document}

\noindent\ColourGuide{MRSON}

\noindent\ColourGuide{LPON}

\noindent\ColourGuide{a}

\end{document}

Responder3

Isso usa um ponto e vírgula como terminador. \def\CGparse#1#2;colocará o primeiro token (letra) #1e tudo antes do ponto e vírgula em #2. Ele se autodenomina recursivamente até #2is \empty.

\documentclass{book}
\usepackage[x11names]{xcolor}

\newcommand\ColourGuide[1]{Colour code:{\count1=0\relax\CGparse#1;}}

\def\CGparse#1#2;{\def\A{#1}%
  \def\B{#2}%
  \ifnum\count1=0\relax
    \space
  \else
    \ifx\B\empty\relax
      { and }%
    \else
      {, }%
    \fi
  \fi
  \advance\count1 by 1
  \def\C{M}\ifx\A\C\relax\textcolor{violet}{metal ion}\fi
  \def\C{R}\ifx\A\C\relax\textcolor{Green3}{residue}\fi
  \def\C{L}\ifx\A\C\relax\textcolor{teal}{ligand}\fi
  \def\C{S}\ifx\A\C\relax\textcolor{Yellow3}{substrate}\fi
  \def\C{P}\ifx\A\C\relax\textcolor{DarkOrange1}{phosphorus}\fi
  \def\C{O}\ifx\A\C\relax\textcolor{red}{oxygen}\fi
  \def\C{N}\ifx\A\C\relax\textcolor{RoyalBlue4}{nitrogen}\fi
  \ifx\B\empty\relax
    {.  }%
  \else 
    \CGparse#2;
  \fi}

\begin{document}

\ColourGuide{MRSON}

\end{document}

Responder4

Já existem muitas respostas boas e provavelmente o meu uso pgfkeysé muito complicado e complicado, mas foi isso que eu descobri.

  • Não há necessidade lualatex(que foi solicitado explicitamente aqui, mas talvez alguém possa usar isso em outro lugar).
  • Os átomos sempre serão listados na mesma ordem, não importa se você escreve \ColourGuide[ligand,residue]ou \ColourGuide[residue,ligand]. Isso pode ser desejado ou não, mas acho que é um bom estilo manter a mesma ordem.

É claro que os argumentos/chaves opcionais poderiam ser reduzidos para, por exemplo, \ColourGuide[L,R]quase sem esforço.

Resultado

\documentclass{article}

% create 'if's for each atom
\newif\ifmetalion
\newif\ifresidue
\newif\ifligand
\newif\ifsubstrate
\newif\ifphosphorus
\newif\ifoxygen
\newif\ifnitrogen

% create two counters
\newcounter{numtrue} % total number of 'if's which are true
\newcounter{currval} % counter (for correctly putting 'and' at the last atom)

% colors
\usepackage[x11names]{xcolor}

% create pgfkeys
\usepackage{pgfkeys,xcolor}
\pgfkeys{
    /colourguide/.is family, /colourguide/.cd,
    default/.style={
        metalion=false,
        residue=false,
        ligand=false,
        substrate=false,
        phosphorus=false,
        oxygen=false,
        nitrogen=false,
    },
    metalion/.is if=metalion,
    residue/.is if=residue,
    ligand/.is if=ligand,
    substrate/.is if=substrate,
    phosphorus/.is if=phosphorus,
    oxygen/.is if=oxygen,
    nitrogen/.is if=nitrogen
}

% this will produce the adequate delimiter between different atoms
\def\chooseDelimiter{%
    \stepcounter{currval}% increment counter
    \ifnum\value{currval}<\value{numtrue}\relax%     if more than one atom remains ...
        ,\ %                                         ... put ',' ...
    \else%                                           
        \ifnum\value{currval}=\value{numtrue}\relax% ... if only one atom remains ...
            \ and\ %                                 ... put 'and' ...
        \else%                                       ... if no atom remains ...
            .%                                       ... put '.'
        \fi%
    \fi%
}

% main command: \ColorGuide
\newcommand\ColourGuide[1][]{%
    % do pgfkeys magic
    \pgfkeys{/colourguide, default, #1}%
    % get number of requested atoms
    \setcounter{currval}{1}%
    \setcounter{numtrue}{0}%
    \ifmetalion  \stepcounter{numtrue}\fi%
    \ifresidue   \stepcounter{numtrue}\fi%
    \ifligand    \stepcounter{numtrue}\fi%
    \ifsubstrate \stepcounter{numtrue}\fi%
    \ifphosphorus\stepcounter{numtrue}\fi%
    \ifoxygen    \stepcounter{numtrue}\fi%
    \ifnitrogen  \stepcounter{numtrue}\fi%
    % build sentence
    Colour code:\ %
    \ifmetalion\textcolor{violet}{metal ion}\chooseDelimiter\fi%
    \ifresidue\textcolor{Green3}{residue}\chooseDelimiter\fi%
    \ifligand\textcolor{teal}{ligand}\chooseDelimiter\fi%
    \ifsubstrate\textcolor{Yellow3}{substrate}\chooseDelimiter\fi%
    \ifphosphorus\textcolor{DarkOrange1}{phosphorus}\chooseDelimiter\fi%
    \ifoxygen\textcolor{red}{oxygen}\chooseDelimiter\fi%
    \ifnitrogen\textcolor{RoyalBlue4}{nitrogen}\chooseDelimiter\fi%
}

\begin{document}
    \paragraph{Works with one atom:}
    \ColourGuide[metalion]
    
    \paragraph{Works with two atoms:}
    \noindent\ColourGuide[residue,ligand]\\ % two atoms
    
    \paragraph{Works with many atoms:}
    \ColourGuide[metalion,residue,ligand,substrate,phosphorus,oxygen,nitrogen]\\ % many atoms
    
    \paragraph{Keeps the given order, no matter what is the order in brackets:}
    \ColourGuide[ligand, residue]
\end{document}

informação relacionada