マクロを通じて引数が提供される場合に、必要な場合にのみ単語の先頭に接頭辞を付けるコマンドの問題

マクロを通じて引数が提供される場合に、必要な場合にのみ単語の先頭に接頭辞を付けるコマンドの問題

次のコードを検討してください。これ答えは、接頭辞が欠落している場合にのみ、単語に接頭辞を追加します。

\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基本関数が与えられた場合、その関数に結果を渡す前に1つ以上の引数を処理するバリアントを生成できます。たとえば、関数に引数指定子(コロンの後のビット)がある場合、 (展開)nを持つバリアントを定義できます。oonce) またはe(展開eの代わりに xhaustively をn使用します。その後は、必要な場所でその変形を使用するだけです。

この場合、2つの関数のバリエーションが必要です

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

バリアントは処理前に引数を展開するため、3行すべてが同じ結果になります。

完全なコード:

\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

ここに画像の説明を入力してください

関連情報