Проблема с командой, которая добавляет префиксы к словам только в случае необходимости, когда аргументы указаны через макросы

Проблема с командой, которая добавляет префиксы к словам только в случае необходимости, когда аргументы указаны через макросы

Рассмотрим следующий код, полученный изэтотответ, где он добавляет префикс к слову, только если префикс отсутствует.

\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

\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}

\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}

\begin{document}
\forcebeginwith{fancycolor}{fancy}    \\% OK: fancycolor
\forcebeginwith{color}{fancy}         \\% OK: fancycolor
\forcebeginwith{\mystringc}{\prefixc} \\% NOT WORKING: fancyfancycolor
\end{document}

ВОПРОС:Как это сделать, учитывая, что мне нужно, чтобы команда была расширяемой?

решение1

Учитывая базовую функцию expl3, вы можете сгенерировать вариант, который обрабатывает один или несколько аргументов перед передачей результатов этой функции. Например, если функция имеет спецификатор аргумента (бит после двоеточия) n, вы можете определить вариант, который имеет o(expandоnce) или e(расширитьеxhaustively) вместо n. Затем вы просто используете вариант везде, где это необходимо.

В этом случае нам нужны варианты двух функций

\cs_generate_variant:Nn \str_range:nnn { enn }

Это гарантирует \str_range:ennсуществование. Этот вариант расширит первый аргумент перед передачей его функции \str_range:nnnдля обработки.

\cs_generate_variant:Nn \str_count:n { e }

Это гарантирует \str_count:eсуществование, которое расширяет свой единственный аргумент перед передачей его в \str_count:n.

Затем мы можем использовать эти варианты так же, как и базовые функции.

\NewExpandableDocumentCommand { \forcebeginwith } { m m }
  {
    \str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
      {#1}
      { #2#1 }
  }

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

Полный код:

\documentclass[border=6pt,varwidth]{standalone}
\ExplSyntaxOn
\cs_generate_variant:Nn \str_range:nnn { enn }
\cs_generate_variant:Nn \str_count:n { e }
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
  {
    \str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
      {#1}
      { #2#1 }
  }
\ExplSyntaxOff

\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}

\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}

\begin{document}
\forcebeginwith{fancycolor}{fancy}    \par% OK: fancycolor
\forcebeginwith{color}{fancy}         \par% OK: fancycolor
\forcebeginwith{\mystringc}{\prefixc} \par% NOT WORKING: fancyfancycolor
\end{document}

решение2

Вот пример:

\documentclass[border=6pt,varwidth]{standalone}
\ExplSyntaxOn
\cs_generate_variant:Nn \str_range:nnn  { enn }
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
  {
    \str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
      {#1}
      { #2#1 }
  }
\ExplSyntaxOff

\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}

\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}

\begin{document}
\forcebeginwith{fancycolor}{fancy}    \\% OK: fancycolor
\forcebeginwith{color}{fancy}         \\% OK: fancycolor
\forcebeginwith{\mystringc}{\prefixc} \\% NOT WORKING: fancyfancycolor
\end{document}

решение3

Лучшим стилем программирования является определение команды уровня пользователя в терминах внутренней функции.

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand { \forcebeginwith } { m m }
 {
  \vincent_forcebeginwith:ee { #1 } { #2 }
 }
\cs_new:Nn \vincent_forcebeginwith:nn
 {
  \str_if_eq:eeF {#2} { \str_range:nnn {#1} { 1 } { \str_count:n {#2} } } { #2 }
  #1
 }
\cs_generate_variant:Nn \vincent_forcebeginwith:nn { ee }

\ExplSyntaxOff

\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}

\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}

\begin{document}

\forcebeginwith{fancycolor}{fancy}    % OK: fancycolor

\forcebeginwith{color}{fancy}         % OK: fancycolor

\forcebeginwith{\mystringc}{\prefixc} % OK: fancycolor

\end{document}

Как вы видите \vincent_forcebeginwith:nn, определен, но в команде уровня пользователя мы используем его вариант, который полностью раскрывает свои аргументы перед передачей их в \vincent_forcebeginwith:nn.

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

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