人们一致认为不应该$...$
使用\(...\)
\ensuremath
里面newcommand
(或,...)定义来NewDocumentCommand
包装在数学模式下排版的传递的宏参数:
\documentclass{article}
\begin{document}
\newcommand*{\somecommand}[1]{
\(#1\)
}
\somecommand{Hello!}
\end{document}
这里,Hello!
将被排版为数学,但该宏的用户/作者可能永远不知道是什么击中了他们。这留下了一些不足之处,可能会让用户感到非常惊讶。它应该可以工作,例如,像\somecommand{$Hello!$}
,其中\newcommand
定义省略进入数学模式。作者应该熟悉并了解数学和文本模式。
现在,我有一个命令应该结合宏参数输入更多的数学,在本例中是一个等号:
\documentclass{article}
\begin{document}
\newcommand*{\somecommand}[1]{
#1\(=\)
}
\somecommand{\(A\)}
\end{document}
但这会破坏数学间距:
我们实际上有\(A\)\(=\)
。这没有什么意义。我们不能定义\somecommad
为有\(#1=\)
:当#1
只是文本时这有效,但如果它已经是数学模式(LaTeX Error: Bad math environment delimiter
)则不行。这种情况将扩展为\(\(A\) = \)
。
问题是:为什么这不起作用?
\(
over的优点$
是可以匹配左右分隔符。从\ensuremath
上面链接的例子中,很明显为什么等效的 with$
不起作用:$ $A$ = $
是合法语法($$A$ = $
不是),但完全没用(A
在文本模式下)。为什么嵌套 LaTeX 内联数学分隔符\(
不起作用?它可以忽略任何内部\(...\)
对。从技术上讲,它没有理由混淆(与 相对$
)(?)。
为了解决上述问题(有一个附加等号/一些更多的数学输入),似乎只有两种解决方案,而且都很糟糕:
- 有
#1\(=\)
,破坏间距并需要人工干预\,
。 - 有
\(#1=\)
。间距有效,但输入参数有处于文本模式。这对于 IDE、linters 等来说非常糟糕(会将数学模式字符(比如下划线)标记为错误,因为它们将在数学模式之外使用)。
编辑:要求提供有关该问题的更多背景信息。该上下文相当长;我试图将其保持在可用的最短范围内。
我正在根据课程创建考试模板exam
。格式要求如下:
- 页面顶部有该页面的问题。
- 下面是一个方框,用于填写该问题的答案(或部分答案)。答案的类型可以灵活(通常是一组所需的方程式或一幅画)。
- 在那个大盒子下面,可能豆未知其他框的数量(0、1、...)用于进一步划分学生的答案。
- 所有这些应该自动垂直填充当前页面。
- 最后,考试结束后,将提供一份解答表以供将来参考。答案应该,感谢
exam
功能,答案应该可以切换并“自动”填写。这是引出上述问题的核心问题(调用者应该在数学模式下输入参数,但这会“破坏”间距,也就是说我们需要手动干预才能获得正确的间距,但我想知道因为嵌套\(...\)
在技术上应该是任意可能的)
得益于tcolorbox
,上述内容可以很好地实现:
\documentclass[
% answers,
]{exam}
\usepackage[
raster,
skins,
% theorems,% `math` key
]{tcolorbox}
\usepackage{amsmath}
\usepackage{etoolbox}
\NewDocumentCommand{\answerblock}{mmmm}{%
\tcbitem[
raster multicolumn=3,% Full width
title={Rearranged equation (symbolic)},
equal height group=A,% All boxes in this group are forced to the same height
% No matter the boxes natural height, conditionally leave some space for manual
% answer entries:
minimum for current equal height group=2cm,
]
% Problem: the caller will pass the argument already set in math mode (set
% inside `\( ... \)` -> DO NOT USE `$...$`). See also
% https://tex.stackexchange.com/q/34830/120853 .
% I asked about this here:
% https://tex.stackexchange.com/q/593218/120853
% We cannot put that argument *inside* another outer pair of `\(...\)`, it
% will break.
% This forces use to chain multiple math environments. This breaks the natural
% spacing these have. Very sad and ugly, but we can hack a bit of space via
% `\,`.
% NOTE: DO NOT put text spaces here, they *will* show up in the result, since
% we are in text mode in between the multiple math environments.
#1\({}={}\)\ifprintanswers#2\fi%
\tcbitem[
raster multicolumn=2,
title={Rearranged equation (numerical values)},
equal height group=A,% All boxes in this group are forced to the same height
% math,% from `theorems`; same issue with nested math ('Bad math environment delimiter')
]
#1\({}={}\)\ifprintanswers#3\fi%
\hfill{}\(=\)%
\tcbitem[
raster multicolumn=1,% 'Right' width
title={Result},
equal height group=A,% All boxes in this group are forced to the same height
halign=center,
]
\ifprintanswers#4\fi%
}
\NewDocumentEnvironment{solutionoranswerarea}{%
d()% Force top box to this height, as a *percentage* of the *remaining* space
O{% Top box descriptive text
Collection of required equations%
}
+b% Environment body itself
}{%
\begin{tcbitemize}[
raster equal height=rows,% Core functionality to automatic sizing, see below
raster every box/.style={
valign=center,% Alignment for *content* inside of boxes
},
]
% The following is just an adaption from '15.6.2 Placing Spaces', see `tcolorbox`
% manual page 312, version 4.42 (2020-10-09).
% The idea is that we have two (the default) columns in an outer raster, each with
% only a *single* row: 2 columns, 1 row.
% However, the rows consist of `tcbitemize` environments, hence we can 'cheat' by
% having two such inner environments in which we can put however many columns and
% rows as we please.
% The `raster equal height=rows` makes it so both *outer* rows are forced to the
% same height through a couple iterations (=compilations); *within* the inner
% `tcbitemize`, we can use a dynamic space macro to adjust a height to match said
% outer height automatically (`space to` and `add to natural height`).
\tcbitem[% First column (of default 2)
blankest,% blankest style sets everything to empty/0pt
space to=\dynamicfillspace,% (Forced height - natural height) -> save to macro
]
\begin{tcbitemize}[% Nested itemization
raster width=2\linewidth,% 2 columns, so double back to original value
raster columns=3,% Full width
]
\tcbitem[
raster multicolumn=3,% Full width
add to natural height=\dynamicfillspace,
title={#2},
]
#3
\end{tcbitemize}
\tcbitem[blankest]% Second column
\begin{tcbitemize}[% Second nested itemization
raster width=0pt,% 'Hide' this entirely
]
\tcbitem[% Fixed height to which the first column will adapt (in height)
blankest,% blankest style sets everything to empty/0pt
height=\textheight-\pagetotal,% https://tex.stackexchange.com/a/207782/120853
]
\end{tcbitemize}
}{
\end{tcbitemize}
}
\begin{document}
\begin{questions}
\question Please solve for \(d\). Write your answer below. Note the required fields.
\begin{solutionoranswerarea}
\begin{solution}
\begin{align*}
a + b &= c \\
c &= 2d \\
\end{align*}
\end{solution}
\answerblock{\(d\)}{\(\frac{a + b}{2}\)}{\(\frac{20 + 10}{2}\)}{15}
\end{solutionoranswerarea}
\clearpage
\question Please solve for \(x\) \emph{and} \(y\).
\begin{solutionoranswerarea}
\begin{solution}
\begin{align*}
z &= x \\
z &= y^{2} \\
\end{align*}
\end{solution}
\answerblock{\(x\)}{z}{9}{9}
\answerblock{\(y\)}{\(\sqrt{z}\)}{\(\sqrt{9}\)}{3}
\end{solutionoranswerarea}
\clearpage
\question Please draw something.
\begin{solutionoranswerarea}[Drawing]
% Automatic solution requires extra work...
\end{solutionoranswerarea}
\end{questions}
\end{document}
打印(lualatex
在 TeXLive 2020 上;需要运行几次才能获得正确的自动间距):
使用answers
课程选项在,它打印(最后一页是相同的,该问题的解决方案不属于这个“M”WE 的一部分):
无法解决此问题的方法有:
- 使用
tcolorbox
定理库及其密钥。这会导致与嵌套时math
相同的问题Bad math environment delimiter
- 我们
\(\answerblock{}{}{}{}\)
甚至无法做到这一点\(\tcbitem ...\)
,也就是在数学模式中包装整个宏。
上述问题仍然存在:
出于各种原因,调用者(即作者)应该控制何时进入数学模式。因此,我们得到了\(...\)
的参数answerblock
。像这样的文本输入\answerblock{...}{...}{\sqrt{9}}{...}
是不可接受的(令人惊讶的、不透明的行为,并且混淆了语法突出显示/linting)。\(\answerblock{}{}{}{}\)
可以但不起作用,所以我们也\TextOrMath
遗憾的是不能使用。
因此,需要手动干预间距,因为我们显然无法嵌套\(...\)
。为什么会这样,有没有办法解决这个问题?\(...\)
应该可以任意嵌套。
答案1
提议:
- 将整个通话内容包含
\answerblock
在内\(
\)
- 不要将各个参数括在数学分隔符中
\answerblock
在命令开始时关闭数学模式\answerblock
在命令末尾重新打开数学模式\tcbitem
在s内使用数学分隔符括住完整的数学表达式
这样,间距就可以保留,无需任何额外的语法,并且编辑器/linter 也可以被欺骗,认为数学是在数学模式下输入的。
MWE(注意 M):
\documentclass[answers]{exam}
\usepackage[raster]{tcolorbox}
% make syntax highlighters happy
\let\mathopen\(
\let\mathclose\)
\usepackage{xparse}
\NewDocumentCommand{\answerblock}{mmmm}{%
\mathclose%
\tcbitem[
title={Rearranged equation (symbolic)},
]
\(#1=\ifprintanswers#2\fi\)%
\tcbitem[
title={Rearranged equation (numerical values)},
]
\(#1=\ifprintanswers#3\fi\)%
\(\hfill{}=\)%
\tcbitem[
title={Result},
]
\ifprintanswers#4\fi%
\mathopen%
}
\begin{document}
\begin{tcbitemize}
% linter also happy
\(\answerblock{d}{\frac{a + b}{2}}{\frac{20 + 10}{2}}{15}\)
\end{tcbitemize}
\end{document}
结果:
答案2
Tex 命令几乎总是应该是数学或文本,而不是两者兼而有之,请注意 latex 具有用于文本和数学重音的\^
符号\hat
,尽管从技术上讲它们可以结合在一起。
然而,如果您确实想将它们合并为一个,LaTeX 可以满足\TextOrMath
您的需求。
\documentclass{article}
\begin{document}
\newcommand*{\somecommand}[1]{\TextOrMath{#1 = \ignorespaces}{#1={}}}
an = in text with word spacing \somecommand{ABC} foo
an = in math with \verb|\mathrel| spacing $\somecommand{ABC}x$
\end{document}