使用 \DeclareKeys/\SetKeys 传递宏参数

使用 \DeclareKeys/\SetKeys 传递宏参数

作为一个练习,我试图以 的方式创建一个 keyval 接口amsthm\newtheoremstylethmtools使用内核的\DeclareKeys而不是keyvalkvsetkeys。 的每个参数都\newtheoremstyle可以轻松存储和检索,除了包含宏参数的最终“head spec”参数#

以下是不起作用但无错误的示例:

\documentclass{article}
\usepackage{amsthm,kantlipsum}

\DeclareKeys[thmstyle]{
    spaceabove .store = \thmstylespaceabove,
    spaceabove .initial:n = \topsep,
    spacebelow .store = \thmstylespacebelow,
    spacebelow .initial:n = \topsep,
    bodyfont .store = \thmstylebodyfont,
    bodyfont .initial:n = \itshape,
    headindent .store = \thmstyleheadindent,
    headindent .initial:n = 0pt,
    headfont .store = \thmstyleheadfont,
    headfont .initial:n = \bfseries,
    headpunct .store = \thmstyleheadpunct,
    headpunct .initial:n = {.},
    postheadspace .store = \thmstylepostheadspace,
    postheadspace .initial:n = 5pt plus 1pt minus 1pt,
    headstyle .code = \def\thmstyleheadcmd##1##2##3{#1},
    % doubling the # below does not work either
    headstyle .initial:n = {\thmname{#1}\thmnumber{ #2}\thmnote{ #3}},
    }

\newcommand{\NewThmStyle}[2]{
    \begingroup
    \SetKeys[thmstyle]{#2}
    \newtheoremstyle{#1}
        {\thmstylespaceabove}
        {\thmstylespacebelow}
        {\thmstylebodyfont}
        {\thmstyleheadindent}
        {\thmstyleheadfont}
        {\thmstyleheadpunct}
        {\thmstylepostheadspace}
        {\thmstyleheadcmd{##1}{##2}{##3}}
    \endgroup
    }
        
\NewThmStyle{teststyle}{}

\newtheorem{theorem}{Theorem}

\theoremstyle{teststyle}
\newtheorem{test}{Test}
        
\begin{document}

\begin{theorem}
\kant[2][1]
\end{theorem}

\begin{test}
\kant[2][1]
\end{test}

\end{document}

韓

我尝试定义一个\thmstyleheadcmd带有三个参数的命令,将其插入到 的最后一个参数中\newtheoremstyle,但它似乎被忽略了。然而,它并没有被视为空,因为对于 amsthm 来说,这应该意味着“默认”,但你可以看到名称和数字之间没有空格。

上述尝试是在这次更简单的尝试之后进行的:

headstyle .store = \thmstyleheadstyle,
headstyle .initial:n = {\thmname{#1}\thmnumber{ #2}\thmnote{ #3}},

并在 的定义\thmstyleheadcmd{##1}{##2}{##3}中用替换。这与上面的结果相同。\thmstyleheadstyle\NewThmStyle

amsthm定义中的相关代码块\newtheoremstyle

  \@ifempty{#9}{%
    \let\thmhead\thmhead@plain
  }{%
    \@namedef{thmhead@#1}##1##2##3{#9}%
    \@temptokena\@xp{\the\@temptokena
      \@xp\let\@xp\thmhead\csname thmhead@#1\endcsname}%
  }%

这让我觉得可能需要增加的数量#,但我无法让任何变化发挥作用。有没有办法使用将的值传递headstyle\newtheoremstyle“逐字” l3keys?还是我遗漏了一些显而易见的东西?

答案1

您不能用来\begingroup保留键的初始值,因为这会使新的定理样式在\endgroup找到后立即变得未定义。

\documentclass{article}
\usepackage{amsthm,kantlipsum}

\newcommand{\thmstyleheadcmd}{}% initialize

\ExplSyntaxOn

\keys_define:nn { mbert/thmstyle }
  {
    spaceabove .tl_set:N = \l_mbert_thmstyle_spaceabove_tl,
    spacebelow .tl_set:N = \l_mbert_thmstyle_spacebelow_tl,
    bodyfont .tl_set:N  = \l_mbert_thmstyle_bodyfont_tl,
    headindent .tl_set:N = \l_mbert_thmstyle_headindent_tl,
    headfont .tl_set:N = \l_mbert_thmstyle_headfont_tl,
    headpunct .tl_set:N = \l_mbert_thmstyle_headpunct_tl,
    postheadspace .tl_set:N = \l_mbert_thmstyle_postheadspace_tl,
    headstyle .code = \cs_set:Nn \mbert_thmstyle_headcmd:nnn{#1},
  }

\tl_new:N \l_mbert_thmstyle_default_tl
\keys_precompile:nnN { mbert/thmstyle }
  {
    spaceabove = \topsep,
    spacebelow = \topsep,
    bodyfont = \itshape,
    headindent = 0pt,
    headfont = \bfseries,
    headpunct = {.},
    postheadspace = 5pt plus 1pt minus 1pt,
    headstyle = \mbert_thmstyle_name:n{#1}\mbert_thmstyle_number:n{~#2}\mbert_thmstyle_note:n{~#3},
  }
  \l_mbert_thmstyle_default_tl

\cs_new_protected:Nn \mbert_thmstyle_name:n { \thmname{#1} }
\cs_new_protected:Nn \mbert_thmstyle_number:n { \thmnumber{#1} }
\cs_new_protected:Nn \mbert_thmstyle_note:n { \thmnote{#1} }

\NewDocumentCommand{\NewThmStyle}{mm}
  {
    \tl_use:N \l_mbert_thmstyle_default_tl
    \keys_set:nn { mbert/thmstyle } {#2}
    \mbert_thmstyle_new:nVVVVVVVe{#1}
      \l_mbert_thmstyle_spaceabove_tl
      \l_mbert_thmstyle_spacebelow_tl
      \l_mbert_thmstyle_bodyfont_tl
      \l_mbert_thmstyle_headindent_tl
      \l_mbert_thmstyle_headfont_tl
      \l_mbert_thmstyle_headpunct_tl
      \l_mbert_thmstyle_postheadspace_tl
      {\mbert_thmstyle_headcmd:nnn{##1}{##2}{##3}}
  }

\cs_new_eq:NN \mbert_thmstyle_new:nnnnnnnnn \newtheoremstyle
\cs_generate_variant:Nn \mbert_thmstyle_new:nnnnnnnnn { nVVVVVVVe }


\ExplSyntaxOff

\NewThmStyle{teststyle}{
  spaceabove=20pt,
  headfont=\normalfont,
  bodyfont=\bfseries\itshape,
  headstyle={#2 -- #1}
}

\NewThmStyle{foo}{}

\newtheorem{theorem}{Theorem}

\theoremstyle{teststyle}
\newtheorem{test}{Test}

\theoremstyle{foo}
\newtheorem{testnormal}{Testnormal}
        
\begin{document}

\begin{theorem}
\kant[2][1]
\end{theorem}

\begin{test}
\kant[2][1]
\end{test}

\begin{testnormal}
\kant[2][1]
\end{testnormal}

\end{document}

在此处输入图片描述

答案2

如果你对 TeX 底层的编程范式不太熟悉,我会尝试给出一个粗略的概述:

当 TeX 处理 .tex 输入文件时,该文件的内容将被视为一组指令,用于创建所谓的标记并将其附加到标记流。

例如,如果 .tex-input-file 包含This is a \macro{with argument} in \LaTeX.,TeX 会根据需要逐渐形成以下标记,以便为进一步处理做好准备:

T类别 11(字母)的显式字符标记:类别 11(字母)的 显式字符标记 :类别 11(字母)的显式字符标记:类别 11(字母)的 显式字符标记: 类别 10(空格)的显式空格字符标记 -表示空格,即,在 ASCIII 和 unicode 中代码点编号均为 32 的字符:类别 11(字母)的 显式字符标记:类别 11(字母)的 显式字符标记: 类别 10(空格)的显式空格字符标记:类别 11(字母)的 显式字符标记:类别 10(空格)的显式空格字符标记:类别 11(字母)的显式字符标记: 类别 10(空格)的 显式空格字符 标记:控制字标记:类别 1(开始组) 的 显式字符标记:类别 11(字母)的 显式字符标记:类别 11(字母)的 显式字符标记:类别 11(字母)的 显式字符标记: 显式类别 10(空格)的空格字符标记:类别 11(字母)的 显式字符标记:类别 11(字母)的显 式字符标记:类别 11(字母)的 显式字符标记:类别 11(字母)的 显式字符标记:类别 11(字母)的 显式字符标记:类别 11(字母)的显式 字符标记:类别 11(字母)的 显式字符标记:类别 11(字母)的显 式字符标记:类别 2(结束组)的 显式字符标记: 类别 10(空格)的显式空格字符标记:类别 11(字母)的 显式字符标记: 类别 11(字母)的 显式字符标记: 类别 10(空格)的显式空格字符标记: 控制字标记:类别 12(其他)的 显式字符标记:T11
hh11
ii11
ss11
10
ii11
ss11
10
aa11
10
\macro\macro
{{1
ww11
ii11
tt11
hh11
10
aa11
rr11
gg11
uu11
mm11
ee11
nn11
tt11
}}2
10
ii11
nn11
10
\LaTeX\LaTeX
..12

即,根据需要,您将获得附加在标记流中的以下标记:

T11​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​。h11i11s1110i11s1110a1110\macro{1w11i11t11h1110a11r11g11u11m11e11n11t11}210i11n1110\LaTeX.12

因此,可以将标记看作是将小项一个接一个地放置,从而形成一个标记队列/标记流。TeX 中的大多数处理都与此类标记有关。

TeX 中的扩展概念是关于通过其他方式获取这些漂亮的小标记项,而不仅仅是“查看”.tex 输入文件并根据其中的内容形成标记。TeX 中的标记可以通过读取和标记 .tex 输入来生成。标记也可以在扩展过程中生成。

TeX 中的宏编程概念是让 TeX 的“扩展站”从标记流中移除当前定义为宏的标记项,并从标记流中抓取一组标记项作为宏参数,并在标记流中用另一组标记替换已移除的标记项,该组标记由在定义宏时形成 ⟨ 的那些标记组成定义⟩ 的 ⟨替换文本⟩,但有⟨替换文本⟩ 的参数被作为参数抓取的标记所替换。

因此,(La)TeX 中的宏编程就是翻转标记流中这些漂亮的小标记项,从而修改标记流中标记的顺序。

TeX 的“token-production-station”一点一点地只生成后续站能够执行下一项任务所需的 token 数量。
因此,当 TeX 的“token-production-station”生成一个 token 并将其附加到 token 流中以传输到后续的处理“站”时,该 token 到达的第一个站是“expansion-station”。如果“expansion-station”发现此 token 是可扩展的,例如,是宏 token,则“expansion-station”会友好地要求“token-production-station”生成并发送适合形成宏 token 参数的 token 集。仅此而已。然后进行扩展,其中的内容被替换。使用生成的 token 集(其中的内容被替换),如果“expansion-station”发现第一个 token 是可扩展的,则以相同的方式对该 token 进行扩展。如果“扩展站”发现该令牌不可扩展,则该令牌将被发送到后续的处理“站”。因此,扩展可以描述为“反刍过程”。

在后续的“站”中,将查看标记并完成与扩展无关的工作。例如,在后续的“站”中,可以将标记用作定义宏、打开或关闭本地范围 (!)、创建框/执行排版工作以生成文档页面、将消息写入屏幕或 .log 文件、写入外部文本文件、将某些内容添加到 .dvi 或 .pdf 文件等的指令。

如果后续“站”需要更多令牌才能完成工作,它们就需要从“扩展站”提供令牌。“扩展站”又需要从“令牌生成站”提供令牌,进行扩展并交付生成的令牌。

这就是为什么你可以\hbox\macro在“说”之后再说“说” \def\macro{{stuff}}

\hbox在 token-production-station 中生成控制字 token \hbox。这恰好是一个不可扩展的原语,因此会通过扩展站而不会被替换/移除。当它到达生产水平框的站时,“水平框生产站”需要更多 token。因此 token-production-station 生成 token \macro。这在“扩展站”中被扩展,因此被 token​​​​​​ 替换。 这些 token 中的每一个都不是可扩展的,因此“扩展站”不会对它们中的任何一个进行任何替换,而是将它们留在原处,这样它们都会进入“水平框生产站”,现在,形成指令​​​​​​​​的所有 token都已到达,并且生成 a 的工作已完成。{1s11t11u11f11f11}2
\hbox{1s11t11u11f11f11}2\hbox

但在此之前有一个指令\def\macro{{stuff}}。使用该指令,“令牌生产站”生产令牌\def并将其发送到“扩展站”。扩展站发现它是一个不可扩展的原语并将其发送出去。当该令牌到达“宏定义站”时,“宏定义站”要求“扩展站”提供更多令牌,但不进行扩展。因此,“扩展站”要求“令牌生产站”生产和交付更多令牌。“令牌生产站”生产并交付令牌​​​​​​​​, “扩展站”将它们原封不动地发送到后续站,以便它们到达“宏定义站”。 (使用而不是“宏定义站”将不需要“扩展站”在不扩展令牌的情况下交付令牌,但允许“扩展站”照常工作。){1{1s11t11u11f11f11}2}2
\edef\def


在尝试粗略概述之后,让我们来看看您的问题中提到的问题:

  1. 如果不在\ExplSyntaxOn/expl3 模式下,代码中的空格在很多地方都会起作用,您需要对此挑剔,并且可能需要%在这里和那里使用以防止出现空格标记。
  2. 使用最新的 TeX 发行版,并且可以使用原语\expanded和,你可以结合和通过 -handler toplevel-expanded 定义宏,以获得形成它们的标记 ⟨\unexpanded\expanded\unexpanded.store替换文本⟩s。(顺便说一句:由于它.initial:n来自:nexpl3-syntax,我想知道为什么它不是.store:N。)
  3. 在宏扩展过程中,宏的 ⟨ 中出现单个类别 6(参数)的哈希字符标记 ( )#6定义⟩ 的 ⟨替换文本⟩ 后面跟着一个属于类别 12(其他)的数字字符标记, , , , , , , , , , ,则表示要用宏参数替换的参数。但是,在 ⟨ 中出现了两个属于类别 6(参数)的连续井号字符标记 ( )112212312412512612712812912#6#6替换文本⟩ 只是折叠成一个不作为参数的东西,但是,像 ⟨替换文本⟩,按原样插入到标记流中。因此,哈希值应进入⟨替换文本⟩ 宏\thmstyleheadcmd,这样它们就不会被当作 ⟨ 的参数替换文本⟩ 但按原样交付,需要加倍。⟨ 内的哈希值加倍替换文本⟩ 的 ⟨定义\edef⟩ 可以通过与结合\unexpanded来实现\edef\macro{\unexpanded{At the time of expanding, the following yields a single hash character token of category 6(parameter): #}}
\documentclass{article}
\usepackage{amsthm,kantlipsum}

\DeclareKeys[thmstyle]{%
  spaceabove .store = \thmstylespaceabove,
  spaceabove .initial:n = \topsep,
  spacebelow .store = \thmstylespacebelow,
  spacebelow .initial:n = \topsep,
  bodyfont .store = \thmstylebodyfont,
  bodyfont .initial:n = \itshape,
  headindent .store = \thmstyleheadindent,
  headindent .initial:n = 0pt,
  headfont .store = \thmstyleheadfont,
  headfont .initial:n = \bfseries,
  headpunct .store = \thmstyleheadpunct,
  headpunct .initial:n = {.},
  postheadspace .store = \thmstylepostheadspace,
  postheadspace .initial:n = 5pt plus 1pt minus 1pt,
  % Let's define \thmstyleheadcmd in a way where hashes going
  % into the replacement text are doubled and thus not taken for
  % parameters of the macro
  headstyle .code = \edef\thmstyleheadcmd{\unexpanded{#1}},
  headstyle .initial:n = {\thmname{#1}\thmnumber{ #2}\thmnote{ #3}},
}

\newcommand{\NewThmStyle}[2]{%
  \begingroup
  % \show\thmstyleheadcmd
  \SetKeys[thmstyle]{#2}%
  % \show\thmstyleheadcmd
  \expanded{%
    \endgroup
    % \show\noexpand\thmstyleheadcmd
    \unexpanded{\newtheoremstyle{#1}}%
    \unexpanded\expandafter{\expandafter{\thmstylespaceabove}}%
    \unexpanded\expandafter{\expandafter{\thmstylespacebelow}}%
    \unexpanded\expandafter{\expandafter{\thmstylebodyfont}}%
    \unexpanded\expandafter{\expandafter{\thmstyleheadindent}}%
    \unexpanded\expandafter{\expandafter{\thmstyleheadfont}}%
    \unexpanded\expandafter{\expandafter{\thmstyleheadpunct}}%
    \unexpanded\expandafter{\expandafter{\thmstylepostheadspace}}%
    \unexpanded\expandafter{\expandafter{\thmstyleheadcmd}}%
  }%
}
        
\NewThmStyle{teststyle}{headstyle=Something\thmname{#1}Something\thmnumber{ #2}Something\thmnote{ #3}}

\newtheorem{theorem}{Theorem}

\theoremstyle{teststyle}
\newtheorem{test}{Test}
        
\begin{document}

\begin{theorem}
\kant[2][1]
\end{theorem}

\begin{test}
\kant[2][1]
\end{test}

\begin{test}[Note]
\kant[2][1]
\end{test}


\end{document}

在此处输入图片描述


如果你碰巧使用的是 TeX\DeclareKeys发行版,而底层 TeX 引擎由于某些不为人知的原因不提供\expanded\unexpanded,这种情况非常非常不可能,你可以 - 而不是组合\edef\unexpanded-\edef\the令牌寄存器的扩展组合以实现哈希加倍。你可以组合顶层扩展\expanded通过和\unexpanded来获取形成由 keyval 接口定义的宏的顶层扩展的令牌然后关闭组,而是通过\expandafter连续交换参数来组合顶层扩展,保存形成顶层扩展结果的令牌,直到大括号组包含所有宏的顶层扩展的结果并且对 的调用\newtheoremstyle被放在令牌后面\endgroup

\documentclass{article}
\usepackage{amsthm,kantlipsum}

\newcommand\PassFirstToSecond[2]{#2{#1}}%
\newtoks\Scratchtoks

\DeclareKeys[thmstyle]{%
  spaceabove .store = \thmstylespaceabove,
  spaceabove .initial:n = \topsep,
  spacebelow .store = \thmstylespacebelow,
  spacebelow .initial:n = \topsep,
  bodyfont .store = \thmstylebodyfont,
  bodyfont .initial:n = \itshape,
  headindent .store = \thmstyleheadindent,
  headindent .initial:n = 0pt,
  headfont .store = \thmstyleheadfont,
  headfont .initial:n = \bfseries,
  headpunct .store = \thmstyleheadpunct,
  headpunct .initial:n = {.},
  postheadspace .store = \thmstylepostheadspace,
  postheadspace .initial:n = 5pt plus 1pt minus 1pt,
  headstyle .code = \expandafter\PassFirstToSecond\expandafter{\the\Scratchtoks}{%
                        \Scratchtoks={#1}\edef\thmstyleheadcmd{\the\Scratchtoks}\Scratchtoks=%
                      },
  headstyle .initial:n = {\thmname{#1}\thmnumber{ #2}\thmnote{ #3}},
}

\newcommand{\NewThmStyle}[2]{%
  \begingroup
  %\show\thmstyleheadcmd
  \SetKeys[thmstyle]{#2}%
  \expandafter\PassFirstToSecond\expandafter{\thmstyleheadcmd}{% 1
  \expandafter\PassFirstToSecond\expandafter{\thmstylepostheadspace}{% 2
  \expandafter\PassFirstToSecond\expandafter{\thmstyleheadpunct}{% 3
  \expandafter\PassFirstToSecond\expandafter{\thmstyleheadfont}{% 4
  \expandafter\PassFirstToSecond\expandafter{\thmstyleheadindent}{% 5
  \expandafter\PassFirstToSecond\expandafter{\thmstylebodyfont}{%  6
  \expandafter\PassFirstToSecond\expandafter{\thmstylespacebelow}{% 7
  \expandafter\PassFirstToSecond\expandafter{\thmstylespaceabove}{% 8
    %\show\thmstyleheadcmd
    \endgroup
    %\show\thmstyleheadcmd
    \newtheoremstyle{#1}%
  }}}}}}}}% 87654321
}
        
\NewThmStyle{teststyle}{headstyle=Something\thmname{#1}Something\thmnumber{ #2}Something\thmnote{ #3}}

\newtheorem{theorem}{Theorem}

\theoremstyle{teststyle}
\newtheorem{test}{Test}
        
\begin{document}

\begin{theorem}
\kant[2][1]
\end{theorem}

\begin{test}
\kant[2][1]
\end{test}

\begin{test}[Note]
\kant[2][1]
\end{test}


\end{document}

在此处输入图片描述

答案3

如果您在 a 中定义某些内容\begingroup ... \endgroup(并且您没有将其设为全局),则该定义不会比组存在更长时间。如果您删除包含线,则样式不再被忽略。我添加了一个冒号以使这一点更清晰(尽管很丑陋)。

(丑陋的)冒号表明风格没有被忽视

\documentclass{article}
\usepackage{amsthm,kantlipsum}

\DeclareKeys[thmstyle]{
    spaceabove .store = \thmstylespaceabove,
    spaceabove .initial:n = \topsep,
    spacebelow .store = \thmstylespacebelow,
    spacebelow .initial:n = \topsep,
    bodyfont .store = \thmstylebodyfont,
    bodyfont .initial:n = \itshape,
    headindent .store = \thmstyleheadindent,
    headindent .initial:n = 0pt,
    headfont .store = \thmstyleheadfont,
    headfont .initial:n = \bfseries,
    headpunct .store = \thmstyleheadpunct,
    headpunct .initial:n = {.},
    postheadspace .store = \thmstylepostheadspace,
    postheadspace .initial:n = 5pt plus 1pt minus 1pt,
    headstyle .code = {\def\thmstyleheadcmd##1##2##3{#1}},
    % doubling the # below does not work either
    headstyle .initial:n = \thmname{#1}\thmnumber{ #2}:\thmnote{ #3},
    }

\newcommand{\NewThmStyle}[2]{
%     \begingroup
    \SetKeys[thmstyle]{#2}
    \newtheoremstyle{#1}
        {\thmstylespaceabove}
        {\thmstylespacebelow}
        {\thmstylebodyfont}
        {\thmstyleheadindent}
        {\thmstyleheadfont}
        {\thmstyleheadpunct}
        {\thmstylepostheadspace}
        {\thmstyleheadcmd{##1}{##2}{xx##3}}
%     \endgroup
    }
        
\NewThmStyle{teststyle}{}

\newtheorem{theorem}{Theorem}

\theoremstyle{teststyle}
\newtheorem{test}{Test}
        
\begin{document}

\begin{theorem}
\kant[2][1]
\end{theorem}

\begin{test}
\kant[2][1]
\end{test}

\end{document}

答案4

如果您愿意使用另一个 key=value 实现,则可以使用expkv-cs1,其中您不必应用任何分组或默认重置,因为键由参数转发处理,并且仅在初始定义期间或\ekvcChange设置/更改默认值。

如果您使用 -Variants,Hash您可以简单地使用它\expanded来获取键值,而无需进一步扩展它们(我们需要使用或\ekvcValue保护我们不想扩展的内容)。而且您也不需要关心哈希加倍,在初始分配期间和内部会为您处理该问题。\noexpand\unexpandedexpkv-cs\ekvcChange

\documentclass{article}
\usepackage{amsthm,kantlipsum}
\usepackage{expkv-cs}

\newcommand\NewThmStyle[2]{\NewThmStyleKV{#2}{#1}}
\ekvcHashAndForward\NewThmStyleKV\NewThmStyleDO
  {
     spaceabove    = \topsep
    ,spacebelow    = \topsep
    ,bodyfont      = \itshape
    ,headindent    = 0pt
    ,headfont      = \bfseries
    ,headpunct     = {.}
    ,postheadspace = 5pt plus 1pt minus 1pt
    ,headstyle     = {\thmname{#1}\thmnumber{ #2}\thmnote{ #3}}
  }
\newcommand\NewThmStyleDO[2]
  {%
    \expanded{\noexpand\newtheoremstyle{#2}%
      {\ekvcValue{spaceabove}{#1}}%
      {\ekvcValue{spacebelow}{#1}}%
      {\ekvcValue{bodyfont}{#1}}%
      {\ekvcValue{headindent}{#1}}%
      {\ekvcValue{headfont}{#1}}%
      {\ekvcValue{headpunct}{#1}}%
      {\ekvcValue{postheadspace}{#1}}%
      {\ekvcValue{headstyle}{#1}}}%
  }

\NewThmStyle{teststyle}{}

\newtheorem{theorem}{Theorem}

\theoremstyle{teststyle}
\newtheorem{test}{Test}

\begin{document}

\begin{theorem}
\kant[2][1]
\end{theorem}

\begin{test}
\kant[2][1]
\end{test}

\end{document}

在此处输入图片描述


1expkv-bundle免责声明:我是其中expkv-cs一部分的作者。

相关内容