我正在使用 thmtools 包来创建我的定理环境,并且我希望有一个依赖于定理开始的 headpunct:如果它以枚举开始(即,如果它以代码开始\begin{enumerate}
)那么我想使用一个点.
作为 headpunct,否则我想使用破折号---
作为 headpunct。
我可以定义一个命令\dashorpoint
,使用并根据该命令检查下一个字符\@ifnextchar
,从而得到正确的结果。但是,我无法使用此命令来解决我的问题,因为在 thmtools 中使用时,它不会抓取定理主体的第一个字符。
这个问题有简单的解决方案吗(无需定义额外的定理样式)?
下面的图片也许可以解释我的问题。
我曾经thmtools
创建过这些环境,但理想情况下,我希望使用一种能够自动给出正确输出的单一定理风格。
这里我有一个简单的例子:我想为两种情况定义一个定理样式,并且我想摆脱现在手动添加的 ~ 符号。
\documentclass{article}
\usepackage{amsthm,thmtools}
\declaretheoremstyle[
notefont=\bfseries,
notebraces={}{},
headformat=\NUMBER\NOTE\ ,
headpunct=---,
]{dash}
\declaretheoremstyle[
notefont=\bfseries,
notebraces={}{},
headformat=\NUMBER\NOTE,
headpunct=.
]{point}
\declaretheorem[style=dash, name={}]{f}
\declaretheorem[style=point, name={}]{g}
\begin{document}
\begin{f} [Theorem]
\begin{enumerate}
\item bla blabla blablabla
\item bla blabla blablabla
\end{enumerate}
\end{f}
\bigskip
\begin{g} [Theorem] ~
\begin{enumerate}
\item bla blabla blablabla
\item bla blabla blablabla
\end{enumerate}
\end{g}
\end{document}
答案1
这是一个可能的解决方案。我正在使用thmtools
' postheadhook
键和enumitem
的before*
钥匙,以及\everypar
,测试定理开头是否有列表环境并采取相应措施。这可能看起来有点复杂,但我认为没有一种简单可靠的方法可以做到这一点,而且我认为一旦你理解了它,它就没那么糟糕了。
\documentclass{article}
\usepackage{amsthm,thmtools}
\newif\ifthmstart
\declaretheoremstyle[headpunct=,postheadspace=0pt,bodyfont=\itshape]{dashordot}
\newcommand*\dashordot{~---~}
\newcommand*\dashordothook{%
\thmstarttrue
\everypar\expandafter{\the\everypar\textbf{\dashordot}\thmstartfalse}%
}
\usepackage{enumitem}
\AtBeginDocument{\setlist{before*={\ifthmstart\let\dashordot.\noindent\fi}}}
\declaretheorem[style=dashordot,postheadhook=\dashordothook]{theorem}
\begin{document}
\begin{theorem}
\begin{enumerate}[label={\roman*)},font=\normalfont]
\item This statement is true;
\item and so is this one!
\end{enumerate}
\end{theorem}
\begin{theorem}
The following statements are equivalent:
\begin{enumerate}[label={\roman*)},font=\normalfont]
\item first statement;
\item second statement.
\end{enumerate}
\end{theorem}
\end{document}
解释
无法将headpunct
键与类似的东西一起使用\@ifnextchar
,因为定理头实际上是在框内创建的。通常将这个框的插入延迟到第一个段落的开始,以确保环境开头的\everypar
空格不产生任何作用。但是,如果定理以列表环境开头,则实际上只有在遇到该列表中的第一个时才会插入它。这很有用,因为这意味着我们可以将是否插入 a或 a的决定推迟到第一个段落的开始或这个列表环境的开始。\par
\item
.
---
所以我正在做的事情如下:
- 我将其定义
\dashordot
为~---~
,因此它会默认插入一个破折号。 - 我正在清除
postheadpunct
并设置postheadspace
,0pt
因为我们将手动插入这些。 我正在使用键在定理环境开始时
postheadhook
将条件设置为真,并将和添加到。\ifthmstart
\textbf{\dashordot}
\thmstartfalse
\everypar
的内容
\everypar
通常插入在每个段落的开头,但在这种情况下只会插入一次,因为定理环境已经设置\everypar
为之后会自行清除的内容。参见例如这个答案了解其\everypar
工作原理。- 如果定理不是以列表开头,
\textbf{\dashordot}
则将插入到定理的开头,并且\ifthmstart
也将设置回 false(这样定理中后面出现的列表环境不会受到影响)。 - 如果定理确实以列表开头,则不会发生这种情况,因此
\ifthmstart
在这种情况下在该列表的开头仍然为真,并且定理头尚未插入(\item
将会这样做)。 我正在
before*
使用enumitem
检查是否\ifthmstart
为真。如果为真,它将重新定义\dashordot
为.
并使用 开始一个段落\noindent
。这会影响所有
enumitem
知道的列表环境,我这样做是\AtBeginDocument
因为它应该在声明所有列表环境之后应用,因为有些可能会使用键before
,这会覆盖它(before*
另一方面,只是添加一些内容before
,所以这是安全的)。- 这会导致定理头和
\textbf{\dashordot}
被立即打印出来,并\ifthmstart
重新设置为 false。因为我们现在已经开始了一个段落,这也会导致列表出现在定理环境的第一行下方。