
私はよく数式で頻繁に使用する記号、例えば\d x
微分dxや\v
ベクトルが必要な場合などに短いマクロを使用します。ヴ読みやすくするために、テキストで頻繁に を使用します。ただし、 は\d
次の文字の下のドットとv
ハチェク アクセントを表すため、定義済みマクロと衝突します。これらは上書きしたくありません (参考文献で必要になるかもしれません...)。
そこで、数式モードでのみこれらのマクロを上書きするために、次の方法を思いつきました。
\documentclass{article}
\usepackage{everyhook}
\newcommand{\mathdef}[2]{%
\PushPostHook{math}{\expandafter\def\csname #1\endcsname{#2}}%
\PushPostHook{display}{\expandafter\def\csname #1\endcsname{#2}}}
\mathdef{d}{\mathrm{d}}%
\begin{document}
\d x is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}
ただし、コマンドを通常のマクロのように定義し、\mathdef{\d}{\mathrm{d}}
引数も取れるようにしたいのですが、、などを使ったすべての実験はexpandafter
うまくunexpanded
いかず、いつもの奇妙なエラー メッセージしか表示されません。どうすればいいのか、何かヒントはありますか?
\everymath
さらに、大きなドキュメントでそのように使用すると、パフォーマンスに大きなペナルティが発生すると思いますか?
答え1
私のアイデアは egreg のアイデアと非常に似ていますが、オプションの引数を追加して、math コマンドが引数自体を処理できるようにしたいと考えています。コード:
\documentclass{article}
\usepackage{xparse}
\DeclareDocumentCommand{\mathdef}{mO{0}m}{%
\expandafter\let\csname old\string#1\endcsname=#1
\expandafter\newcommand\csname new\string#1\endcsname[#2]{#3}
\DeclareRobustCommand#1{%
\ifmmode
\expandafter\let\expandafter\next\csname new\string#1\endcsname
\else
\expandafter\let\expandafter\next\csname old\string#1\endcsname
\fi
\next
}%
}
\mathdef{\v}[1]{\tilde{#1}}
\mathdef{\d}{\mathrm{d}}
\begin{document}
Ha\v{c}ek and tilde $\v{a}+\v{b}=1$.
\d x is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}
結果:
答え2
私は使用しません\everymath
。
\documentclass{article}
\usepackage{letltxmacro}
\makeatletter
\newcommand{\mathdef}[2]{%
\@ifundefined{#1}{\@mathdef@new{#1}{#2}}{\@mathdef@remember{#1}{#2}}
}
\newcommand{\@mathdef@remember}[2]{%
\expandafter\LetLtxMacro
\csname textmode@#1\expandafter\endcsname
\csname #1\endcsname
\expandafter\def\csname mathmode@#1\endcsname{#2}%
\expandafter\DeclareRobustCommand\csname#1\endcsname{%
\ifmmode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\csname mathmode@#1\endcsname}{\csname textmode@#1\endcsname}%
}%
}
\newcommand{\@mathdef@new}[2]{%
\expandafter\DeclareRobustCommand\csname#1\endcsname{#2}%
}
\makeatother
\mathdef{d}{\mathop{}\!\mathrm{d}}
\begin{document}
\d{x} is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}
しかし、これは良い方法ではないと思います。混乱を招き、エラーが発生しやすくなります。
見る\LetLtxMacro はいつ使用すればよいですか?の詳細については、 をご覧ください\LetLtxMacro
。
次のようにすると少し簡単になりますetoolbox
:
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand{\mathdef}[2]{%
\@ifundefined{#1}{\@mathdef@new{#1}{#2}}{\@mathdef@remember{#1}{#2}}
}
\newcommand{\@mathdef@remember}[2]{%
\expandafter\robustify\csname#1\endcsname
\csletcs{textmode@#1}{#1}%
\csdef{mathmode@#1}{#2}%
\protected\csdef{#1}{%
\ifmmode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\csuse{mathmode@#1}}{\csuse{textmode@#1}}%
}%
}
\newcommand{\@mathdef@new}[2]{%
\protected\csdef{#1}{#2}%
}
\makeatother
\mathdef{d}{\mathop{}\!\mathrm{d}}
\begin{document}
\d{x} is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}
\DeclareRobustCommand
なぜ(最初のバージョン) または\protected
(2 番目のバージョン) を全面的に使用するのでしょうか?
TeXが書き込み操作を行うときは、モードにはなりません。特に数式モードではありません。次のような単純な定義は、
\newcommand{\foo}{%
\relax % if this comes first in an alignment
\ifmmode
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
\foo@math\foo@text
}
だろういつも\foo@text
で見つかった場合は選択します\write
。上記の保護により、\mathdef
コマンドはそれ自体で書き込まれるため、その時点では選択は行われません\write
。
なぜ を使用しないのですか\everymath
? 次の例を試して確認してください。
\documentclass{article}
\everymath{\let\foo\foomath}
\newcommand{\foo}{Foo}
\newcommand{\foomath}{Ops}
\begin{document}
Text: \foo
Math: $\foo$
Ops: abc\textsuperscript{\foo}
\end{document}
答え3
使用したい\PushPostHook
-マクロあらゆるフック引数を処理するマクロを(再)定義するためのパッケージですか?
問題 1:
#1
LaTeX では、引数は やなどで表されます#2
。つまり、1..9 の範囲の数字が続くハッシュのシーケンスで表されます。
定義をネストする場合は、内部定義のハッシュを 2 倍にする必要があります。
\def\outsidemacro#1{%
\def\insidemacro##1{This is insidemacro's argument: ##1.}%
This is outsidemacro's argument: #1.%
}
拡張中、連続する 2 つのハッシュが 1 つのハッシュに統合され、ハッシュの量が半分になります。
つまり、次\outsidemacro{foo}
のようになります。
\def\insidemacro#1{This is insidemacro's argument: #1.}%
This is outsidemacro's argument: foo.%
\PushPostHook
viaの定義を見ると\show\PushPostHook
次のようになります。
> \PushPostHook=\protected\long macro:
#1#2->\eh@checkhook {#1}\PushPostHook \letcs \eh@tempi {eh@post#1}\expandafter
\gdef \csname eh@post#1\expandafter \endcsname \expandafter {\eh@tempi \eh@hook
separator #2}\undef \eh@tempi .
ご覧のとおり、トークンはパターン の名前を持つマクロ内に保持されます 。\eh@post⟨name of hook⟩
例えば、\eh@postmath
および \eh@postdisplay
。
このようなマクロにトークンを追加するには、\PushPostHook
問題のマクロを次のようにします。\eh@tempi
、問題のトークンをマクロの後ろに追加してマクロを再定義します。拡大の\eh@tempi
。
拡大は\eh@tempi
重要なポイントです:
\eh@tempi
の定義にハッシュ ( ) が含まれている場合#
、展開中に 2 つの連続するハッシュがそのうちの 1 つに縮小されます。
これは次のことを意味します:
または\PushPostHook
にものを追加するために が呼び出されるたびに、または にすでに含まれているものを含む連続ハッシュの数が半分になります。\eh@postmath
\eh@postdisplay
\eh@postmath
\eh@postdisplay
これは、 または\PushPostHook
に何かを追加するために複数回呼び出す場合に特に問題になります。\eh@postmath
\eh@postdisplay
トークン レジスタを使用して を維持することで、連続するハッシュの量が半分になることを回避できます\the
。これは、トークン レジスタの内容が によって「吐き出される」ときに、ハッシュの量が減らないためです。 の間に による「吐き出し」が\the
発生すると\edef
、ハッシュの量は減らないだけでなく、2 倍になります。
例えば、
\myscratchtoks{#}
\edef\mymacro{\the\myscratchtoks}
の定義では、\mymacro
から得られるハッシュの量\myscratchtoks
は 2 倍になります。 を展開すると\mymacro
、その 2 倍になった量は半分になり、したがって の展開は\mymacro
によって提供されるのと同じ量のハッシュを提供します\the\myscratchtoks
。
したがって、トークン レジスタに何かを追加し、 \PushPostHook
そのトークン レジスタを「フラッシュ」するためだけに使用することをお勧めします。
問題2:
\long
引数も処理できるマクロを維持したい場合は、プレフィックスまたはと同様に使用できるものを実装することをお勧めします\global
。
以下の例では、括弧で囲まれた引数の後に括弧でネストされた引数が続く#{
マクロを実装するために -記法を使用しました。マクロの は常に括弧でネストされるため、 の前にあるすべてのトークンを取得するために、左括弧で区切られた引数の処理を使用できます。 このようなトークンには、定義コマンド自体 (またはなど)、(再)定義される制御シーケンス トークン、および があります。\mathcommand
⟨definition text⟩
⟨definition text⟩
\renewcommand*
\global\long\def
⟨parameter text⟩
例えば、
\mathcommand\renewcommand*\mymacrowitharguments[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
の最初の(\mathcommand
左中括弧で区切られた)引数はシーケンスになり\renewcommand*\mymacrowitharguments[2]
、2 番目の引数は中括弧内にネストされた内容によって形成されます。 は、\mbox{math-arg~1: }(#1) \mbox{ math-arg~2: }(#2)
シーケンス
\mathcommand
、つまり、シーケンスをトークン レジスタに追加します。⟨first argument⟩{⟨second argument⟩}
\renewcommand*\mymacrowitharguments[2]{\mbox{math-arg~1: }(#1) \mbox{ math-arg~2: }(#2) }
\mymathhooktoks
また、左中括弧で区切られた引数を取得し、その引数の後ろにある、つまり次のように形成できる制御シーケンス トークンの名前として中括弧内にネストされているものを取得するマクロも実装\mathcommandfromname
しました\csname..\endcsname
。
例えば、
\mathcommandfromname\renewcommand*{mymacrowitharguments}[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
結果:
\mathcommand\renewcommand*\mymacrowitharguments[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
\documentclass{article}
\usepackage{everyhook}
\newtoks\myscratchtoks
\newcommand\mymathhookmacro{}%
\PushPostHook{math}{\mymathhookmacro}%
\PushPostHook{display}{\mymathhookmacro}%
\newcommand{\mathcommand}{}%
\long\def\mathcommand#1#{\innermathcommand{#1}}%
\newcommand{\innermathcommand}[2]{%
\begingroup
\expandafter\myscratchtoks\expandafter{\mymathhookmacro#1{#2}}%
\xdef\mymathhookmacro{\the\myscratchtoks}%
\endgroup
}
\newcommand\exchange[2]{#2#1}%
\newcommand\mathcommandfromname{}%
\long\def\mathcommandfromname#1#{\romannumeral0\innermathcommandfromname{#1}}%
\newcommand\innermathcommandfromname[2]{%
\expandafter\exchange\expandafter{\csname#2\endcsname}{ \mathcommand#1}%
}%
%----------------------------------------------------------------
\newcommand*\mymacrowitharguments[2]{%
non-math-arg~1: \textbf{(#1)} %
non-math-arg~2: \textbf{(#2)}%
}%
\mathcommand\renewcommand*\mymacrowitharguments[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
\newcommand*\myothermacrowitharguments[2]{%
other-non-math-arg~1: \textbf{(#1)} %
other-non-math-arg~2: \textbf{(#2)}%
}%
\mathcommandfromname\renewcommand*{myothermacrowitharguments}[2]{%
\mbox{other-math-arg~1: }(#1)
\mbox{ other-math-arg~2: }(#2)
}%
\mathcommand\renewcommand*\d{\mathrm{d}}%
\parindent=0ex
\begin{document}
\d x is an x with a dot below and $\int f(x) \d x$ is an
integral over $x$.
\bigskip
Testing with \verb|\mymacrowitharguments|:\smallskip
outside math:\\
\mymacrowitharguments{arg A}{arg B}
\smallskip
inside math:\\
$\mymacrowitharguments{arg A}{arg B}$
\bigskip
Testing with \verb|\myothermacrowitharguments|:\smallskip
outside math:\\
\myothermacrowitharguments{arg A}{arg B}
\smallskip
inside math:\\
$\myothermacrowitharguments{arg A}{arg B}$
\end{document}