トークンごとに処理するとコマンドが中断される

トークンごとに処理するとコマンドが中断される

\everymath特定の指定文字をフォーマットする (自動的になどをv挿入する)に入力するコマンドを作成しようとしています\mathbf。その部分は実際にはすでに理解していますが、問題となっているのは処理自体です。数式モード内でコマンドが分離されているようで、正しく表示されないか、完全に壊れています。

これは、ステップ実行するだけで何も変更しない最小限のバージョンです (理論上)。

\ExplSyntaxOn
\NewDocumentCommand{\mformat}{+m}{%
  \exp_after:wN #1 \mode_if_math:TF { \mformat } { }
}
\ExplSyntaxOff

次のように使われます:

\everymath{\mformat}

以下に、それがどのように壊れるかの例をいくつか示します。

\(\vec{v}\)

期待される:期待ベクトル

実際の:実際のベクトル(に相当\vec{}v

\(\mathbf{v}\) % Just gives "Missing } inserted." error

これを修正する方法について何かアイデアはありますか?

編集: 新しく気づいたことがあります。問題のあるコマンドを中括弧で囲むと ( のようにmathbf\({\mathbf{v}}\)問題なく動作します)、突然、完全に動作します。なぜこのようなことが起こるのかはわかりません。


私はegregの回答を解決策としてマークしました。それは私が尋ねた質問に答えたからです。しかし、後世のために、私が尋ねるべきだった質問に対する解決策をここに示します(PhelypeOleinikのコメントに基づく)

\ExplSyntaxOn

% Used to keep track of already active characters
\tl_new:N \g__mformat_mathactive_tl
% Used to figure out which characters need to be made normal again
\tl_new:N \l__mformat_remove_mathactive_tl
% Used to keep track of added characters from *this* iteration
\tl_new:N \l__mformat_used_tl

% Using https://tex.stackexchange.com/a/611898/261875
% and https://tex.stackexchange.com/a/299805/261875
\NewDocumentCommand{\mformat}{m}{
  % By default remove all previous active characters
  \tl_set_eq:NN \l__mformat_remove_mathactive_tl \g__mformat_mathactive_tl
  \tl_set:Nn \l__mformat_used_tl {}

  \tl_if_empty:nTF { #1 } {} {
    % Parse the formatting
    \cs_set:Npn \__mformat_parse:w ##1[##2]##3\relax {
      % Process each character in the set
      \tl_map_inline:nn { ##2 } {
        \tl_if_in:NnTF \g__mformat_mathactive_tl { ####1 } {
          % If this character is already active, keep it active
          \tl_remove_once:Nn \l__mformat_remove_mathactive_tl { ####1 }

          % Check if the character has been used this iteration
          \tl_if_in:NnTF \l__mformat_used_tl {####1} {
            % Helper needed to have something expandable once
            \cs_set_eq:Nc \__mformat_letter_helper: 
            { __mformat_letter_new_####1: }
            % Add a formatting option to the letter
            \cs_set:cx { __mformat_letter_new_####1: }  { 
              \exp_not:N ##1 { \exp_not:o \__mformat_letter_helper: } 
            }
          } {
            % Record that this has been used
            \tl_put_right:Nn \l__mformat_used_tl { ####1 }
            % Define what the letter will now resolve to
            \cs_set:cx { __mformat_letter_new_####1: }  { 
              \exp_not:N ##1 {\mathchar\use:c { __mformat_mathcode_####1: }} 
            }
          }
          
          \char_gset_active_eq:nc { `####1 } { __mformat_letter_new_####1: }
        } {
          % Record that this is now an active character
          \tl_gput_right:Nn \g__mformat_mathactive_tl { ####1 }
          % Record that this has been used
          \tl_put_right:Nn \l__mformat_used_tl { ####1 }
          
          % Record the normal character so it can be used later
          \cs_new:cx { __mformat_mathcode_####1: } 
          { \the\mathcode`####1 }
          
          % Define what the letter will now resolve to
          \cs_new:cx { __mformat_letter_new_####1: }  { 
            \exp_not:N ##1 {\mathchar\use:c { __mformat_mathcode_####1: }} 
          }
          \char_gset_active_eq:nc { `####1 } { __mformat_letter_new_####1: }
          
          % Set the character to be active in math mode
          \char_set_mathcode:nn { `####1 } { "8000 }
        }
      }

      % If there's no more character sets, finish, otherwise recurse
      \tl_if_empty:nTF { ##3 } { } { \__mformat_parse:w ##3\relax }
    }

    % Begin recursive parsing
    \__mformat_parse:w #1\relax
  }

  % \tl_show:N \l__mformat_remove_mathactive_tl
  % Remove the active status from the characters that need it
  \tl_map_inline:Nn \l__mformat_remove_mathactive_tl {
    \tl_gremove_once:Nn \g__mformat_mathactive_tl {##1}
    
    % Reset the math code
    \char_set_mathcode:nn { `##1 } { \use:c { __mformat_mathcode_##1: } }

    % Deregister functions
    \cs_undefine:c { __mformat_letter_new_##1: }
    \cs_undefine:c { __mformat_mathcode_##1: }
  }
}

\NewDocumentCommand{\std}{m}{ \mathchar\use:c { __mformat_mathcode_#1: } }

\ExplSyntaxOff

これは次のように使われます

\mformat{\mathbb[R]\mathbf[vw]}

答え1

これはXY問題に非常に似ています。

そして何も変わらない(理論上は)

申し訳ありませんが、それは違います。

\mode_if_math:TF { \mformat } { }

\if_mode_math: \__prg_TF_true:w \fi: \use_ii:nn {\mformat}{}

$\vec{v}$あなたが持っている場合は、

\vec\if_mode_math: \__prg_TF_true:w \fi: \use_ii:nn {\mformat}{}

したがって の引数は\vecです\if_mode_math:。例:

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\mformat}{+m}{%
  \exp_after:wN #1 \mode_if_math:TF { \mformat } { }
}
\ExplSyntaxOff

\everymath{\mformat}

\renewcommand{\vec}[1]{\showtokens{#1}}

\begin{document}

$\vec{v}$

\end{document}

コンソールで

No file mform.aux.
> \if_mode_math: .
\vec #1->\showtokens {#1}

l.13 $\vec

より良いのは\exp_last_unbraced:Nf

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\mformat}{+m}{%
  \exp_last_unbraced:Nf #1 { \mode_if_math:TF { \mformat } { } }
}
\ExplSyntaxOff

\everymath{\mformat}

\renewcommand{\vec}[1]{\showtokens{#1}}

\begin{document}

$\vec{v}$

\end{document}

コンソールに印刷される場所

> v.
\vec #1->\showtokens {#1}

しかし、これもあまり良くありません。

\mathrm{x}

その結果、長い一連のエラーが発生します。そして、長いケースリストを実行してそれらを修正したとしても、次のようなエラーが発生します。

\mathrm{abc}

に変わる

\exp_last_unbraced:Nf abc { \mode_if_math:TF { \mformat } { } }

それは絶対にあなたが見たいものではありません。

答え2

数式モードのすべての文字のデフォルト フォントはすでに明示的に宣言されているため、v の宣言を調整するだけで済みます。ここでは太字のローマン フォント ( に一致\mathbf) を使用していますが、"予想" の画像では斜体が表示されています。

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

\documentclass{article}

\DeclareSymbolFont{boldrm}     {OT1}{cmr}{bx}{n}
\DeclareSymbolFontAlphabet{\mathbf}   {boldrm}
\DeclareMathSymbol{v}{\mathalpha}{boldrm}{`v}

\begin{document}

$\vec{v} + \vec{w}$


\end{document}

関連情報