수학 모드에서만 정의되는 매크로

수학 모드에서만 정의되는 매크로

\d x나는 자주 사용되는 기호(예 : 미분 dx 또는 \v벡터가 필요한 경우) 에 대한 수학 공식에 짧은 매크로를 자주 사용합니다.V내용을 더 쉽게 읽을 수 있도록 내 텍스트에 자주 사용합니다. 그러나 \d다음 문자 아래의 점과 v재정의하고 싶지 않은 hacek 악센트를 나타내기 때문에 미리 정의된 매크로와 충돌이 발생합니다 (참고문헌에 필요할 수도 있습니다...).

그래서 저는 수학 모드에서만 해당 매크로를 재정의하기 위해 다음을 생각해냈습니다.

\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(두 번째 버전)을 모두 사용하는 이유는 무엇입니까 ?

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-macro를 사용하고 싶습니다 .모든 걸-인수를 처리하는 매크로를 (재)정의하기 위한 패키지?

문제 1:

LaTeX에서 인수는 #1#2등으로 표시됩니다. 즉, 1..9 범위의 숫자 뒤에 해시 시퀀스가 ​​표시됩니다.

중첩 정의의 경우 내부 정의에 대해 해시를 두 배로 늘려야 합니다.

\def\outsidemacro#1{%
  \def\insidemacro##1{This is insidemacro's argument: ##1.}%  
  This is outsidemacro's argument: #1.%
}

확장하는 동안 두 개의 연속 해시가 하나의 해시로 축소됩니다. 즉, 해시 양이 절반으로 줄어듭니다.

즉, 다음과 같은 \outsidemacro{foo}결과가 나옵니다.

\def\insidemacro#1{This is insidemacro's argument: #1.}%  
This is outsidemacro's argument: foo.%

\PushPostHook비아 \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해시가 포함된 경우( #) 확장 중에 두 개의 연속 해시가 그 중 하나로 축소됩니다.

이는 다음을 의미합니다.

또는 \PushPostHook에 항목을 추가해야 할 때마다 이미 있거나 있는 항목과의 연속 해시 양이 절반으로 줄어듭니다.\eh@postmath\eh@postdisplay\eh@postmath\eh@postdisplay

이는 특히 또는 \PushPostHook에 항목을 추가하기 위해 여러 번 호출할 때 문제가 됩니다 .\eh@postmath\eh@postdisplay

\the토큰 레지스터의 내용이 를 통해 "뱉어내면" 해시 양이 줄어들지 않기 때문에 토큰 레지스터를 통해 항목을 유지함으로써 연속 해시 양이 절반으로 줄어드는 것을 방지할 수 있습니다 . \the동안에 "뱉어내기"가 발생하면 \edef해시 양이 줄어들 뿐만 아니라 두 배로 늘어납니다.

만약 그렇게 한다면, 예를 들어,

\myscratchtoks{#}
\edef\mymacro{\the\myscratchtoks}

, 정의에 따르면 \mymacro해시 양이 \myscratchtoks두 배가 됩니다. 확장할 때 \mymacro두 배로 늘어난 양은 절반으로 줄어들므로 확장은 \mymacro에서 전달하는 것과 동일한 양의 해시를 전달합니다 \the\myscratchtoks.

따라서 토큰 레지스터에 항목을 추가하고 \PushPostHook해당 토큰 레지스터를 "플러싱"하는 데에만 사용하는 것이 좋습니다.

문제 2:

인수도 처리할 수 있는 매크로를 유지하려면 접두사 \long또는 와 유사하게 사용할 수 있는 것을 구현하는 것이 좋습니다 \global.

아래 예에서는 중괄호로 묶인 인수 뒤에 오는 왼쪽 중괄호로 구분된 인수를 처리하는 #{매크로를 구현하기 위해 -notation을 사용했습니다. 매크로의 \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]두 번째 인수는 중괄호 안에 중첩된 항목으로 구성됩니다 \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}

여기에 이미지 설명을 입력하세요

관련 정보