我经常需要描述层堆栈中的材料序列,例如以下内容:
钽/铜/钽/铜/钴-铁-硼/氧化镁/钴-铁-硼/钽/钌/金
破折号表示成分不明的合金。我的问题是如何在 LaTeX 中正确排版。
我的 MWE 是
\documentclass{article}
\usepackage{lipsum}
\usepackage{mhchem}
\begin{document}
\lipsum[1]
The layer stack consist of \ce{Ta}/\ce{Cu}/\ce{Ta}/\ce{Cu}/\ce{Co-Fe-B}/\ce{MgO}/\ce{Co-Fe-B}/\ce{Ta}/\ce{Ru}/\ce{Au} and all layers are sputtered in a bla bla bla
Co-Fe
\end{document}
然而,这种做法存在几个问题。
- 斜线后未插入换行符
- 破折号变成了连字符(我认为是长破折号)
- 频繁使用
\ce
看起来很尴尬并且代码几乎无法阅读。
有没有更好的方法可以做到这一点(使用 mhchem)?请注意,大多数出版商(在我们的研究领域)建议使用破折号和斜线,不应被其他符号取代。
答案1
在向下滚动到我的代码之前,请注意,仅仅因为该代码有效并不意味着它是一种好方法。
一般来说,有一种数据结构叫做“逗号列表”。逗号列表在 LaTeX 编程中起着重要作用。例如,在使用时,geometry
我们可能会说\usepackage[top=2cm,left=3cm]{geometry}
。在这种情况下,top=2cm,left=3cm
是一个包含两个项目的逗号列表:top=2cm
和left=3cm
。(它们用逗号分隔,因此得名。)(然后top=2cm
被解释为键值对:top
键和2cm
值。)
同样,您的符号确实是“嵌套逗号列表”。外层称为“堆栈”,是/
其分隔符。内层称为“层”,是-
其分隔符。因此,您需要做的就是模仿这,这或者这迭代嵌套的斜线破折号列表。
由于您的请求相对简单(仅涉及字母和数字),因此简短的 TeX 代码足以说明如何处理您的逗号列表嵌套斜杠破折号列表:
- 首先
\CE
接受一个参数,即完整列表,并将其传递给CEii
。 \CEii
接受两个参数,以 分隔/
。因此第一个参数是第一个 之前的子字符串/
。之后的子字符串成为第二个参数。例如Co-Fe-B/MgO/Co-Fe-B
分为Co-Fe-B
和MgO/Co-Fe-B
。- 现在第一个参数
Co-Fe-B
应该是第一层,将其传递给\Ce
。 - 如果第二个参数不为空,则会出现更多层。插入一个
\newslash
。 - 将第二个参数(其他层
MgO/Co-Fe-B
)视为一个新列表并从头开始。(MgO/Co-Fe-B
变成MgO
和Co-Fe-B
。它们都\Ce
按顺序传递给。另一个\newslash
插入它们之间。) \Ce
和Ceii
的作用与CE
和相同CEii
。不同之处在于它根据 划分字符串-
并插入\newdash
。(Co-Fe-B
变为Co
,Fe
和。)并按顺序B
将这些元素传递给。\ce
- (MgO 不是一种元素......我的错)
- 你的工作是重新定义
\newskash
和\newdash
。
\documentclass{article}
\usepackage{mhchem}
\begin{document}
\def\newslash{///}
\def\newdash{---}
\newif\ifmoreelements
\newif\ifmorelayers
\def\Ce#1{%
\def\templayer{#1}%
\loop%
\expandafter\Ceii\templayer-=%
\expandafter\ce\expandafter{\tempfirstelement}%
\ifmoreelements%
\newdash%
\expandafter\Cei\tempotherelements=%
\repeat}
\def\Cei#1-={%
\def\templayer{#1}}
\def\Ceii#1-#2={%
\def\tempfirstelement{#1}\def\tempotherelements{#2}%
\ifx\tempotherelements\empty\moreelementsfalse\else\moreelementstrue\fi}
\def\CE#1{%
\def\tempstack{#1}%
\loop%
\expandafter\CEii\tempstack/+%
{\expandafter\Ce\expandafter{\tempfirstlayer}}%
\ifmorelayers%
\newslash%
\expandafter\CEi\tempotherlayers+%
\repeat}
\def\CEi#1/+{%
\def\tempstack{#1}}
\def\CEii#1/#2+{%
\def\tempfirstlayer{#1}\def\tempotherlayers{#2}%
\ifx\tempotherlayers\empty\morelayersfalse\else\morelayerstrue\fi}
\CE{Ta/Cu/Ta/Cu/Co-Fe-B/MgO/Co-Fe-B/Ta/Ru/Au}
\end{document}
关于好的方式
有时我听到人们说我们永远不应该使用\def
。原因很明显:使用TeX
语法在某种意义上危险的。例如,如果有人说\CE{-==-+//+-==-}
,它不会按预期工作。此外,还有一些外貌问题。例如,\CE{ Ta // Cu }
将调用带有空格的\ce{ Ta }
和,而应忽略逗号周围的所有空格。\ce{ Cu }
\CE
不过,这完全取决于你。如果你知道你的代码永远不会像这样\CE{-==-+//+-==-}
,并且你确实喜欢这种简单的方式,那么就使用它。但是如果你正在寻找一种强大而安全的方式,那么\DeclareCommaListParser\CE[/][-]{blahblahblah}
就给xparse
它一个机会吧。
对我来说,xparse
到目前为止还很复杂。但是,如果有一天 LaTeX3 发布,并且这些命令有详细的文档,我可能就不用再回答问题了def
。
答案2
对于那些使用chemformula
代替mhchem
有一个快速解决方案。 I 足以替换/
be\slash
以允许在斜线后换行。 由于chemformula
已经有一种在复合词中用输出符号替换输入符号的机制,我们只需要访问它:
\ExplSyntaxOn
\cs_new_protected:Npn \chemformula_new_compound_property:nn #1#2
{ \prop_put_if_new:Nnn \l__chemformula_cmpd_prop {#1} {#2} }
\NewDocumentCommand \NewChemCompoundProperty { mm }
{ \chemformula_new_compound_property:nn {#1} {#2} }
\ExplSyntaxOff
现在只剩下说了\NewChemCompoundProperty{/}{\slash}
。这利用了一个内部变量,所以它不是完全安全的,但我倾向于在包中添加一些类似的东西。
至于-
被转换为单键——同样适用于,chemformula
但使用chemformula
语法"..."
可以在这里有所帮助。或者——使用新命令可以说\NewChemCompoundProperty{:}{-}
(或类似的话):
\documentclass{article}
\usepackage{chemformula,mhchem}
\ExplSyntaxOn
% I might add this to chemformula:
\cs_new_protected:Npn \chemformula_new_compound_property:nn #1#2
{ \prop_put_if_new:Nnn \l__chemformula_cmpd_prop {#1} {#2} }
\NewDocumentCommand \NewChemCompoundProperty { mm }
{ \chemformula_new_compound_property:nn {#1} {#2} }
\ExplSyntaxOff
\NewChemCompoundProperty{/}{\slash}
\usepackage{showframe}
\begin{document}
Bla. The layer stack consists of \ch{Ta/Cu/Ta/Cu/Co "-" Fe "-" B/MgO/Co "-"
Fe "-" B/Ta/Ru/Au} and all layers are sputtered in a bla bla bla
% or even:
\NewChemCompoundProperty{:}{-}
Bla. The layer stack consists of
\ch{Ta/Cu/Ta/Cu/Co:Fe:B/MgO/Co:Fe:B/Ta/Ru/Au} and all layers are sputtered in
a bla bla bla
\end{document}
更新版本 4.10 (2015/03/16) 直接支持此功能:
\documentclass{article}
\usepackage{chemformula}[2015/03/16]
\NewChemCompoundProperty{/}{\slash}
\usepackage{showframe}
\begin{document}
Bla. The layer stack consists of \ch{Ta/Cu/Ta/Cu/Co "-" Fe "-" B/MgO/Co "-"
Fe "-" B/Ta/Ru/Au} and all layers are sputtered in a bla bla bla
% or even:
\NewChemCompoundProperty{:}{-}
Bla. The layer stack consists of
\ch{Ta/Cu/Ta/Cu/Co:Fe:B/MgO/Co:Fe:B/Ta/Ru/Au} and all layers are sputtered in
a bla bla bla
\end{document}
答案3
这可以与新的 RegExp 引擎配合使用。出于好奇,我尝试了一下并找到了解决方案。这是新旧语法的奇怪组合。
\documentclass{article}
\usepackage[version=3]{mhchem}
\usepackage{l3regex}
\begin{document}
\newcommand*\stackslash{\text{/}\allowbreak}
\newcommand*\stackdash{\text{-}\allowbreak}
\ExplSyntaxOn
\newcommand\stack[1] {
\tl_new:N \l_my_tl
\tl_set:Nx \l_my_tl { \exp_not:N \ce { #1 } }
\regex_replace_all:nnN { \/ } { \cE] \c{stackslash} \c{ce}\cB[ } \l_my_tl
\regex_replace_all:nnN { \- } { \cE] \c{stackdash} \c{ce}\cB[ } \l_my_tl
\tl_use:N \l_my_tl
}
\ExplSyntaxOff
The layer stack consist of \stack{Ta/Cu/Ta/Cu/Co-Fe-B/MgO/Co-Fe-B/Ta/Ru/Au} and all layers are sputtered in a bla bla bla
\end{document}
基本上,它接受A/B/C-D/E
并将其转换为\ce{A}\stackslash\ce{B}\stackslash\ce{C}\stackdash\ce{D}\stackslash\ce{E}
。
答案4
这是一个小的 Lua 代码片段,演示了不同的方法,该方法将纯文本(以空格结尾)传递给 Lua,使用正则表达式并将输出传回 TeX 引擎。它将除斜杠和减号之外的一系列文本字符扩展为命令\ce
,将 divis 更改为 endash 并\allowbreak
在每个斜杠后添加命令。
设输入为:Cu/Ta/H2O/Cu/Ta/Cu/Co-Fe-B/MgO/Co-Fe-B/Ta/Ru/Au
。
修改后的文本如下所示:\ce{Cu}/\allowbreak{}\ce{Ta}/\allowbreak{}\ce{H2O}/\allowbreak{}\ce{Cu}/\allowbreak{}\ce{Ta}/\allowbreak{}\ce{Cu}/\allowbreak{}\ce{Co}--\allowbreak{}\ce{Fe}--\allowbreak{}\ce{B}/\allowbreak{}\ce{MgO}/\allowbreak{}\ce{Co}--\allowbreak{}\ce{Fe}--\allowbreak{}\ce{B}/\allowbreak{}\ce{Ta}/\allowbreak{}\ce{Ru}/\allowbreak{}\ce{Au}
。
我们执行lualatex mal-chem.tex
。
\documentclass{article}
\pagestyle{empty}
\usepackage{lipsum}
\usepackage{luacode}
\usepackage[version=3]{mhchem}
\begin{document}
\begin{luacode*}
function malstr(text)
text=string.gsub(text, "[^/-]+", "\\ce{%1}")
text=string.gsub(text, "%-", "--\\allowbreak{}")
-- -- or --\\allowbreak{}
text=string.gsub(text, "/", "/\\allowbreak{}")
tex.print(text); print(text)
end -- of function malstr
\end{luacode*}
\def\nobonds#1 {\directlua{malstr([[#1]])} }
\lipsum[1]\par
The layer stack consist of \nobonds Cu/Ta/H2O/Cu/Ta/Cu/Co-Fe-B/MgO/Co-Fe-B/Ta/Ru/Au and all layers are sputtered in...
% result is: \ce{Cu}/\allowbreak{}\ce{Ta}/\allowbreak{}\ce{H2O}/\allowbreak{}\ce{Cu}/\allowbreak{}\ce{Ta}/\allowbreak{}\ce{Cu}/\allowbreak{}\ce{Co}--\allowbreak{}\ce{Fe}--\allowbreak{}\ce{B}/\allowbreak{}\ce{MgO}/\allowbreak{}\ce{Co}--\allowbreak{}\ce{Fe}--\allowbreak{}\ce{B}/\allowbreak{}\ce{Ta}/\allowbreak{}\ce{Ru}/\allowbreak{}\ce{Au}
\end{document}