根据我之前的问题xparse
我注意到(恕我直言)用普通的 TeX来制作带有分隔参数的宏并不容易\def
。据我所知,LaTeX 方式 - \newcommand
- 根本没有定义这种类型参数的机制。应该说有xparse
一种创建此类参数的机制,但仍然存在一些问题。
这是另一个例子,其中用 创建特殊分隔的参数非常容易\def
,但使用机制来完成可能需要一些技巧xparse
。
\def\braces(#1#2|#3#4){
\ensuremath{
\int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2
}
}
所以我想我会再次向社区询问如何使用xparse
(可能与 LaTeX3 结合使用或仅使用 LaTeX3)来做到这一点的建议。我希望这对我以及阅读此问题的人都有启发。此外,正确且现代的 LaTeX 定义命令的方式不是,\def
甚至不再是\newcommand
使用,而是使用xparse
。
答案1
我猜你只想要那个\chi
部分。
\documentclass{article}
\usepackage{amsmath}
\NewDocumentCommand{\braces}{>{\SplitArgument{1}{|}}r()}{\bracesaux#1}
\NewDocumentCommand{\bracesaux}{mm}{\bracesauxaux#1#2}
\NewDocumentCommand{\bracesauxaux}{mmmm}{%
\chi_{#1}(1)\chi_{#2}(2)\chi_{#3}(1)\chi_{#4}(2)%
}
\begin{document}
\[
\braces(ab|cd)
\]
\end{document}
这是否比 更好\def
,您来判断吧。
答案2
\NewDocumentCommand
等(' ')的理念ltcmd
是,它提供了一种轻松创建“类似 LaTeX”命令的方法。“类似 LaTeX”意味着主要使用 中的强制参数、{...}
中的可选参数[..]
、用于命令的“特殊替代”版本的星号等。但是,它也涵盖了一些更广泛的情况,最明显的是beamer
-like 可选<..>
、图片模式(如强制)(..)
和逐字抓取(类似\verb
但有一些区别)。这涵盖了文档中您想要的很多内容,但它确实不是包括对任意材料的深入解析。(灵活性的目的是覆盖足够的输入范围,以便大多数事情都可以使用来完成ltcmd
。)
对于更复杂的情况,需要使用经典的 TeX 构造(或使用等效构造)来构建想法expl3
。在大多数情况下,这将发生之内常规参数。例如,siunitx
以“非标准”方式解析数字,但文档级命令使用签名\num
定义。人们可能会将 TikZ 视为一个极端的例子:它定义了自己的输入语法,这绝对不是标准 LaTeX,但它是自洽的 - 但仅在环境或类似范围内可用。ltcmd
O{}m
tikzpicture
请注意,一个关键思想是ltcmd
将文档命令语法与实现分开。这意味着,一般来说,如果您使用某种分隔的输入格式,那么单独实现仍然是明智的:这允许重新处理或重新使用一个或另一个方面,而不受另一个方面的限制。
我的建议是在定义非标准之前仔细考虑可预测性文档命令语法。
答案3
编辑:TeX - LaTeX Stack Exchange 成员数学 在评论中提请该答案初始版本的作者注意,下划线 ( _
) 在 expl3 中没有类别 8(下标),但有类别 11(字母),因此不能在 expl3 中用于数学下标,所以在 expl3 中,需要使用隐式字符/_
之一来代替下划线 ( )作为数学下标。\sb
\c_math_superscript_token
故意将错误的工具用于某项任务并不是一个好主意。即使是 ltcmd/xparse,无论它有多现代,也不是万能的。有些任务最好用 ltcmd/xparse 以外的工具来完成,因为 ltcmd/xparse 不是为这些任务而设计的。所以不要专注于用 ltcmd/xparse 做这类事情。
再次使用\cs_new_protected:Npn
expl3/LaTeX 3 — 这样做没有错:
\ExplSyntaxOn
\cs_new_protected:Npn\braces(#1#2|#3#4){
\ensuremath{
\int \frac{\chi\sb#1(1)\chi\sb#2(1)\chi\sb#3(2)\chi\sb#4(2)}{r\sb{12}}~dV\sb1~dV\sb2
}
}
\ExplSyntaxOff
我没有检查公式的输入是否可以改进。我保留了\ensuremath
代码,因为您使用了它。如果实现由我决定,\ensuremath
我会要求用户知道宏仅在数学模式下有效,而不是使用。\ensuremath
是产生不良排版的陷阱。例如,您会看到人们试图通过排列\ensuremath
在 TeX 处于水平模式时执行的命令来排版公式。这样,要排版的公式片段就会被排版,从而产生不良的排版,而不是让 TeX 切换到数学模式并一次性生成正确的公式。
[以下评论仅代表个人观点:]
除此之外,我还采取了一些可能在幕后切换排版模式的命令,这会引起一些困惑:当我撰写文档时,我必须决定并了解文本短语的类型,从而了解排版模式。当我想写一段文本时,我让 TeX 切换到水平模式。当我想输入数学时,我让 TeX 切换到数学模式(内联或显示)。我希望自己控制它。;-)
我没有找到在 ltcmd/xparse 中完美实现此目的的方法:
在实现某种参数分隔符处理时可能考虑的参数类型有:
r
和R
和d
和D
,但是使用这些,您必须在参数之前和之后指定非空分隔符,除此之外,分隔符必须由单个标记组成。e
和E
,但像d
和D
装饰参数是可选的,因此如果您省略了通过以下方式实现的分隔符e
/E
/d
/D
-type-argument 实现的分隔符,除非您自己实现错误检查,否则可能不会收到错误消息。此外,如果 embellishment-argument 由多个标记组成或留空,则必须将其括在花括号中,而 TeX 的分隔参数则不需要这样做。
在您的特定情况下,当参数的分隔符由单个标记组成时,您可以应用带有分隔符的 D 类型参数,(
并)
默认|
使用预处理器(如\SplitArgument
或)\SplitList
进行拆分|
并将其结果提供给辅助宏,该宏处理两个参数并传递错误消息或制作四个错误消息,然后将其提供给另一个辅助宏,该宏处理四个参数并传递标记,扩展后将进入 TeX 的排版机制 - 这样,您可以自己管理错误处理和错误消息文本,并且如果)
缺少右括号,可能会出现低级 TeX 错误:
\documentclass{article}
%---------------------------------------------------------------------
% With older LaTeX releases you need this, with recent ones you don't:
\ifx\IfBlankTF\UndEFiNEd
\ExplSyntaxOn
\cs_new_eq:NN \IfBlankTF \tl_if_blank:nTF
\ExplSyntaxOff
\fi
%---------------------------------------------------------------------
\NewDocumentCommand {\braces} {>{\SplitArgument{1}{|}}D(){|}} {%
\bracesi#1%
}
\makeatletter
\NewDocumentCommand {\bracesi} {mm} {%
\IfNoValueTF{#2}{\@secondoftwo}{%
\IfBlankTF{#2}{\@secondoftwo}{%
\expandafter\IfBlankTF\expandafter{\@firstoftwo{}#2}{\@secondoftwo}{%
\IfBlankTF{#1}{\@secondoftwo}{%
\expandafter\IfBlankTF\expandafter{\@firstoftwo{}#1}{\@secondoftwo}{%
\@firstoftwo
}%
}
}%
}%
}%
{\bracesii#1#2}%
{\message{^^J^^J!!!\on@line: Cannot get four arguments from the pattern!!!^^J}}%
}
\makeatother
\NewDocumentCommand {\bracesii} {mmmm} {%
\ensuremath{%
\int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
}%
}
\begin{document}
\braces(ab|cd)
% \braces()
% \braces(|)
% \braces(a|)
% \braces(|b)
% \braces(a|b)
% \braces(a|bc)
% \braces(ac|b)
% \braces(ac|)
% \braces(a|bc)
% \braces(ab)
% \braces ab
% \braces c)
% \braces cd)
% \braces(AB|C % ) missing - low level error
% \braces(AB % ) missing - low level error
\end{document}
或者你定义一个带有 D 类型参数和分隔符(
和|
默认为空的宏,它将|
附加的该参数提供给一个辅助宏,该辅助宏处理一个 m 类型参数,表示和之间的东西是否(
形成|
两个参数和另外两个 m 类型参数,表示和之间的两个参数(
和|
带有分隔符|
和和默认为空的 D 类型参数,然后将所有这些参数提供给另一个处理四个参数并传递标记的宏,这些标记在扩展后将进入 TeX 的排版机制,或者传递一条错误消息 - 这样你可以自己管理错误处理和错误消息文本,并在缺少和/或)
时获取低级 TeX 错误消息:|
)
\documentclass{article}
%---------------------------------------------------------------------
% With older LaTeX releases you need this, with recent ones you don't:
\ifx\IfBlankTF\UndEFiNEd
\ExplSyntaxOn
\cs_new_eq:NN \IfBlankTF \tl_if_blank:nTF
\ExplSyntaxOff
\fi
%---------------------------------------------------------------------
\makeatletter
\NewDocumentCommand {\braces} {D(|{}} {%
\IfBlankTF{#1}{\@secondoftwo}{%
\expandafter\IfBlankTF\expandafter{\@firstoftwo{}#1}{\@secondoftwo}{\@firstoftwo}%
}%
{\bracesi{\@firstoftwo}#1|}%
{\bracesi{\@secondoftwo}{}{}|}%
}
\NewDocumentCommand {\bracesi} {mmmD|){}} {%
#1{%
\IfBlankTF{#4}{\@secondoftwo}{%
\expandafter\IfBlankTF\expandafter{\@firstoftwo{}#4}{\@secondoftwo}{\@firstoftwo}%
}%
}{\@secondoftwo}%
{\bracesii{#2}{#3}#4}%
{\message{^^J^^J!!!\on@line: Cannot get four arguments from the pattern!!!^^J}}%
}
\makeatother
\NewDocumentCommand {\bracesii} {mmmm} {%
\ensuremath{%
\int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
}%
}
\begin{document}
\braces(ab|cd)
% \braces() % | missing - low level error
% \braces(|)
% \braces(a|)
% \braces(|b)
% \braces(a|b)
% \braces(a|bc)
% \braces(ac|b)
% \braces(ac|)
% \braces(a|bc)
% \braces(ab) % | missing - low level error
% \braces ab % ) missing - low level error
% \braces c)
% \braces cd)
% \braces(AB|C % ) missing - low level error
% \braces(AB % | missing - low level error
\end{document}
答案4
问题中的代码引入了额外的空格。下面,使用 some 删除了这些空格%
。
然后,对于\braces(abc|xyz)
,c
和z
不在下标中,如下所示。
\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
\ensuremath{%
\int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
}%
}
\begin{document}
\braces(abc|xyz)
\end{document}
即使有\braces(a{bc}|x{yz})
,c
和也不z
在下标中,如下所示。
\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
\ensuremath{%
\int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
}%
}
\begin{document}
\braces(a{bc}|x{yz})
\end{document}
原因是周围没有牙套#1
原因是周围\chi_#1
等等。
如果添加括号\chi_{#1}
,则c
和z
位于下标中。
现在假设ab
应该放在第一个下标和xy
第三个下标中。然后\braces({ab}c|{xy}z)
就可以使用了,如下所示。
\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
\ensuremath{%
\int \frac{\chi_{#1}(1)\chi_{#2}(1)\chi_{#3}(2)\chi_{#4}(2)}{r_{12}} dV_1 dV_2%
}%
}
\begin{document}
\braces({ab}c|{xy}z)
\end{document}
现在假设c|d
应该放在第二个下标中。代码\braces({ab}c|d|{xy}z)
给出的结果如下。
\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
\ensuremath{%
\int \frac{\chi_{#1}(1)\chi_{#2}(1)\chi_{#3}(2)\chi_{#4}(2)}{r_{12}} dV_1 dV_2%
}%
}
\begin{document}
\braces({ab}c|d|{xy}z)
\end{document}
可以使用 来修复此问题\braces({ab}{c|d}|{xy}z)
,如下所示。
\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
\ensuremath{%
\int \frac{\chi_{#1}(1)\chi_{#2}(1)\chi_{#3}(2)\chi_{#4}(2)}{r_{12}} dV_1 dV_2%
}%
}
\begin{document}
\braces({ab}{c|d}|{xy}z)
\end{document}
此时,使用\braces{ab}{c|d}{xy}{z}
4 对括号进行输入可能会更方便。这种语法可以用\newcommand
或轻松定义\NewDocumentCommand
轻松定义此类语法。