Wie kann ich einen Satz basierend auf der Eingabe eines Befehls ändern?

Wie kann ich einen Satz basierend auf der Eingabe eines Befehls ändern?

Ich schreibe einen Bericht, der Enzymbilder wie diese enthält:

Bildbeschreibung hier eingeben

Ich \captionmöchte einen Farbleitfaden einbinden, damit wichtige Komponenten/Atome farblich beschrieben werden können (dieser Bericht wird nicht veröffentlicht, daher ist dies im Hinblick auf Farbenblindheit kein Problem). Ich verwende derzeit einen Befehl wie diesen:

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

Bei manchen Bildern sind jedoch nicht alle Farbkomponenten vorhanden, sodass es nicht sinnvoll wäre, redundante Farbcodes einzufügen. Wie kann ich einen Satz basierend auf Eingaben erstellen? Beispiel:

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

würde ergeben:

Farbcode: Metallion, Rückstand, Substrat, Sauerstoff und Stickstoff.

in den angegebenen Farben. Ich verwende lualatexund habe mir die Verwendung angesehen lua(was nett wäre), aber ich weiß nicht, wie ich die beiden richtig (oder effizient) interagieren lassen soll, wie könnten die Argumente beispielsweise wie in Python mit extrahiert werden input[0]? Ich würde mich über jeden Rat oder jede Lösung über jede Methode freuen, aber es luawäre nett, wenn ich anfangen könnte, es zu lernen und es auf andere Befehle anzuwenden, die ich lualatexhäufig verwende.

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}

Wie es aussieht:

Bildbeschreibung hier eingeben

(Ich bin nicht sicher, welche Tags ich hier anbringen soll)

Antwort1

Guter Versuch in Ihrer Antwort, aber …

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

Bildbeschreibung hier eingeben

Es ist kein Zählen erforderlich: Das Argument wird Zeichen für Zeichen zugeordnet und der entsprechende Code wird der Sequenz hinzugefügt, die später mit den entsprechenden Trennzeichen verwendet werden kann.

Um eine Code-Duplikation zu vermeiden, ist es vielleicht besser, das Argument leer zu lassen, wenn Sie die vollständige Liste wünschen.

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

Die Ausgabe ist die gleiche.

Antwort2

Dank der Kommentare konnte ich eine Lösung zusammenstellen, die zwar nicht schön ist, aber wie gewünscht funktioniert. Hinzufügen einer Antwort von @egreg zuSo bestimmen Sie die Anzahl der Zeichen im Argument eines Befehlsund die verlinkte Antwort @John Kormylokommentiertergibt folgendes:

Bildbeschreibung hier eingeben

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

Antwort3

Dies verwendet ein Semikolon als Abschlusszeichen. \def\CGparse#1#2;fügt das erste Token (den Buchstaben) in #1und alles vor dem Semikolon in ein #2. Es ruft sich selbst rekursiv auf, bis #2ist \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}

Antwort4

Es gibt bereits viele gute Antworten, und meine Verwendung pgfkeysist wahrscheinlich viel zu kompliziert und umständlich, aber das ist, was mir eingefallen ist.

  • Nicht erforderlich lualatex(was hier explizit angefragt wurde, aber vielleicht kann es jemand woanders gebrauchen).
  • Die Atome werden immer in der gleichen Reihenfolge aufgelistet, egal ob Sie \ColourGuide[ligand,residue]oder schreiben \ColourGuide[residue,ligand]. Dies kann erwünscht sein oder nicht, aber ich denke, es ist ein guter Stil, die gleiche Reihenfolge beizubehalten.

Natürlich könnten die optionalen Argumente/Schlüssel \ColourGuide[L,R]fast ohne Aufwand auf „zB“ gekürzt werden.

Ergebnis

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

verwandte Informationen