Как изменить предложение в зависимости от ввода команды?

Как изменить предложение в зависимости от ввода команды?

Я пишу отчет, включающий изображения ферментов, такие как это:

введите описание изображения здесь

В \captionя хотел бы включить цветовой гид, чтобы ключевые компоненты/атомы можно было описать цветом (этот отчет не публикуется, поэтому в отношении дальтонизма это не проблема). В настоящее время я использую команду типа этой:

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

Однако в некоторых изображениях присутствуют не все цветные компоненты, поэтому не стоит включать избыточные цветовые коды. Как создать предложение на основе ввода? Например:

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

будет производить:

Цветовой код: ион металла, остаток, субстрат, кислород и азот.

в указанных цветах. Я использую lualatexи рассматривал использование lua(что было бы неплохо), но я не знаю, как правильно (и эффективно) взаимодействовать с ними, как можно извлечь аргументы, например, как в Python с помощью input[0]? Я был бы признателен за любые советы или решения любым методом, но было бы неплохо, чтобы я мог начать изучать его и применять к другим командам, которые я часто luaиспользую .lualatex

МВЭ:

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

Как это выглядит:

введите описание изображения здесь

(Я не уверен, какие теги сюда поставить)

решение1

Хорошая попытка ответить, но…

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

введите описание изображения здесь

Подсчет не требуется: аргумент отображается посимвольно, и соответствующий код добавляется к последовательности, которую впоследствии можно использовать с подходящими разделителями.

Возможно, лучше, чтобы избежать дублирования кода, оставить аргумент пустым, если вам нужен полный список.

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

Результат тот же.

решение2

Благодаря комментариям, мне удалось собрать воедино решение, которое не очень красиво, но работает так, как требуется. Добавление ответа от @egreg вкак определить количество символов в аргументе командыи связанный ответ @John Kormyloпрокомментировалдает это:

введите описание изображения здесь

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

решение3

Здесь в качестве терминатора используется точка с запятой. \def\CGparse#1#2;поместит первый токен (букву) в #1, а все, что находится до точки с запятой, в #2. Он вызывает себя рекурсивно, пока #2не достигнет \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}

решение4

Уже есть много хороших ответов, и, возможно, мой вариант pgfkeysслишком сложен и громоздок, но вот что я придумал.

  • В этом нет необходимости lualatex(о чем здесь явно просили, но, возможно, кто-то сможет использовать это где-то еще).
  • Атомы всегда будут перечислены в одном и том же порядке, независимо от того, пишете ли вы \ColourGuide[ligand,residue]или \ColourGuide[residue,ligand]. Это может быть желательно или нет, но я думаю, что это хороший стиль — сохранять тот же порядок.

Конечно, необязательные аргументы/ключи можно было бы сократить до eg \ColourGuide[L,R]практически без усилий.

Результат

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

Связанный контент