类定理环境中列表的引用/将 # 符号写入文件

类定理环境中列表的引用/将 # 符号写入文件

提前提醒一下:这篇文章会很长。过去几天,我花了不少时间试图解决以下问题:我正在排版数学讲义,并使用该ntheorem包定义各种定理类环境,经常遇到以下形式的情况

\begin{mythm}\begin{enumerate}
  \item\label{a}
  \item\label{b}
\end{enumerate}\end{mythm}

理想情况下输入(就我而言,因为我使用该cleveref包)

\cref{b}

应该产生形式为“定理 3 (b)”的东西(即包括标签所在定理环境的名称和编号)。

事实证明这相当困难,而且记录也不是很完善。主要问题是涉及两个计数器(enumi我们称之为定理计数器thmcnt),以及定理名称。

我的第一次尝试是,使用该etoolbox包,侵入环境mythm,每次启动时创建一个新的宏,保存定理名称和编号,并可以使用命令进行格式化(和引用)cleveref,例如

\BeforeBeginEnvironment{mythm}{
   \crefname{\labelcode}{Theorem~\thethmcnt}
   \edef\Label#1{\noexpand\label[\labelcode]{#1}}
}

此外,\labelcode对于此环境调用还应包含一些独特的内容,例如

\edef\labelcode{ctr@thm@\roman{chapter}@\roman{section}@\arabic{thmcnt}

而且,我们环境的执行,我们需要记住将计数器增加一(完成后将其放回原位),否则保存的定理计数器\crefname将会偏离一。

因此,理想情况下,在上面的例子中,我们可以写

\begin{mythm}\begin{enumerate}
  \item\Label{a}
  \item\Label{b}
\end{enumerate}\end{mythm}

并且\cref{b}应该能做我们想要它做的事情。不幸的是,据我所知,cleveref忽略了 之后的所有\crefname命令\begin{document},所以事情没那么简单。

我当时尝试将所有格式信息写入一个文件,然后让 LaTeX 下次读取它,这样在编译文档两次后,所有链接信息都可以访问。例如

\newread\foo
\immediate\openin\foo=\filename
\ifeof\foo\relax\else\input\filename\relax\fi
\immediate\closein\foo
\newwrite\blah
\immediate\openout\blah=\filename
\AtEndDocument{\immediate\write\blah{\string\endinput}\relax
   \immediate\closeout\blah}

然后将上面的相应行替换为

\immediate\write\blah{\string\crefname{\labelcode}{Theorem~\thethmcnt}{}}

这似乎有效,尽管在我看来,对于一个(我认为是)相对常见的问题来说,这似乎相当复杂。如果有人(仍在阅读;))并且知道一个更简单的解决方案,我会很高兴并且有兴趣知道!

不过,还有一个小缺点。当cleveref与一起使用时hyperref,它还会将所有引用变成可点击的链接。然而,在当前解决方案中,只有“(b)”变成了超引用。显而易见的方法是使用cleverefs\crefformat命令,但对于此目的,它的语法不切实际,也就是说,我们必须编写类似这样的代码

\crefformat{\labelcode}{#2Theorem~\thethmcnt~#1#3}

在我们的\BeforeBeginEnvironment区块中,但这当然有和之前一样的问题,\thethmcnt产生了我们所处的定理的数量引用时而不是我们所引用的定理。

因此我尝试像上面一样将其简单地写入我们的文件中

\immediate\write\blah{\noexpand\crefformat{\labelcode}{#2Theorem~\thethmcnt~#1#3}}

但不幸的是,这不起作用,这就是我陷入困境的地方:将其写入文件不起作用,因为会#被替换为##,这会导致 LaTeX 读取文件时出错。如果在重新运行 LaTeX 之前在输出文件中手动替换,它实际上会起作用,##但这#不是一个非常令人满意的解决方案。我想可以编写一个外部脚本并在每次编译时将其与 LaTeX 一起调用,或者使用命令\write18或类似的东西,但这不利于协作或跨平台实现,所以有人知道 LaTeX 内部解决方案吗?

我已经尝试过更改 catcode#或尝试通过\char类似命令访问它,但这些都不起作用,总是导致类似

! Illegal parameter number in definition of \@groupformat.

有人有什么意见或想法吗?感谢您读到这里 :)

编辑:此功能现已包含在coolthms包中,可在氯化三乙胺

答案1

您可以使用以下方法将哈希字符写入#外部文件。我用虚拟宏替换了一些宏,以保持代码简洁。

\documentclass{article}

\begingroup
\catcode`\#=12
\gdef\hashchar{#}%
\endgroup

% Alternative
\edef\althashchar{\string#}%

% dummy macros
\def\labelcode{LABEL}
\def\thethmcnt{thethmcnt}
\def\crefformat#1#2{}
\chardef\blah=1\relax% write to .aux file

\begin{document}

% Works
\immediate\write\blah{\noexpand\crefformat{\labelcode}%
   {\hashchar2Theorem\string~\thethmcnt\string~\hashchar1\hashchar3}}

% Works as well
\immediate\write\blah{\noexpand\crefformat{\labelcode}%
   {\althashchar2Theorem\string~\thethmcnt\string~\althashchar1\althashchar3}}

% Works too
\immediate\write\blah{\noexpand\crefformat{\labelcode}%
   {\string#2Theorem\string~\thethmcnt\string~\string#1\string#3}}

% Now inside a macro:
\def\mywritemacro{%
% Works
\immediate\write\blah{\noexpand\crefformat{\labelcode}%
   {\hashchar2Theorem\string~\thethmcnt\string~\hashchar1\hashchar3}}

% Works as well
\immediate\write\blah{\noexpand\crefformat{\labelcode}%
   {\althashchar2Theorem\string~\thethmcnt\string~\althashchar1\althashchar3}}

% Works too
\immediate\write\blah{\noexpand\crefformat{\labelcode}%
   {\string##2Theorem\string~\thethmcnt\string~\string##1\string##3}}
}
\mywritemacro

\end{document}

结果文件(此处.aux):

\relax 
\crefformat {LABEL}{#2Theorem~thethmcnt~#1#3}
\crefformat {LABEL}{#2Theorem~thethmcnt~#1#3}
\crefformat {LABEL}{#2Theorem~thethmcnt~#1#3}
\crefformat {LABEL}{#2Theorem~thethmcnt~#1#3}
\crefformat {LABEL}{#2Theorem~thethmcnt~#1#3}
\crefformat {LABEL}{#2Theorem~thethmcnt~#1#3}

答案2

无论如何,enumerate当您真正想要一个subtheorem带有自己的计数器的环境时,请远离使用该环境。

\documentclass{article}


\usepackage{ntheorem}
%\usepackage{amsthm}

\usepackage{thmtools}
\usepackage{enumitem}
\usepackage{hyperref}

\usepackage{cleveref}

\declaretheorem[name=My Theorem,
    ]{mythm}
% yes, this boilerplate could be automated: do it for every theorem.
% in theory, wasting counters could be avoided by use of counter aliasing,
% but that would require patching of enumitem.
\newlist{submythm}{enumerate}{1}
\crefname{submythmi}{My Theorem}{My Theorems}
\setlist[submythm]{label=(\alph*),%
  ref=\themythm (\alph*)}

% dynamically turn into the propery submythm, sublemma, whatnot.
\makeatletter
\newenvironment{subs}{%
  \edef\subname{sub\thmt@envname}%
  \expandafter\begin\expandafter{\subname}% enumitem requires explicit begin
}{%
  \expandafter\end\expandafter{\subname}%
}
\makeatother


\begin{document}
\begin{mythm}\begin{subs}
  \item\label{a} Hello!
  \item\label{b} Hello yourself!
\end{subs}\end{mythm}

\begin{enumerate}
  \item bim!\label{c}
\end{enumerate}

Those were \ref{a} and \ref{b} and \ref{c}

Those were \cref{a} and \cref{b} and \cref{c}
\end{document}

编辑:这种变体允许\ref,但它会在下一个定理之前产生 1 (a) ,这可能不是你想要的。(可能可以通过谨慎使用 来修复\p@foo,但我认为如果你有定理 1 A...b...推论1 A...b...定理 1 的证明...推论 1 的证明...:不清楚在哪里可以找到对(A)

答案3

需要说明的是,虽然\crefname必须在前言中使用,但较低级别的\crefformatet al. 命令即使在 之后也能正常工作。因此,如果您使用而不是 ,\begin{document}您的原始解决方案可能有效。\crefformat\crefname

另一方面,Ulrich 的解决方案似乎更加优雅。

相关内容