我正在使用自定义命令来方便编写和阅读 LaTeX 方程式,例如:
\newcommand{\bbA}{\mathbb{A}}
\newcommand{\bbB}{\mathbb{B}}
\newcommand{\bbC}{\mathbb{C}}
% etc...
\newcommand{\mcA}{\mathcal{A}}
\newcommand{\mcB}{\mathcal{B}}
\newcommand{\mcC}{\mathcal{C}}
% etc...
\newcommand{\msA}{\mathscr{A}}
\newcommand{\msB}{\mathscr{B}}
\newcommand{\msC}{\mathscr{C}}
% etc...
\newcommand{\mfA}{\mathfrak{A}}
\newcommand{\mfB}{\mathfrak{B}}
\newcommand{\mfC}{\mathfrak{C}}
% etc...
\newcommand{\mfa}{\mathfrak{a}}
\newcommand{\mfb}{\mathfrak{b}}
\newcommand{\mfc}{\mathfrak{c}}
% etc...
但是,这占用了文件头中的 130 行代码(幸运的是,我没有手写,而是编写了一个程序,这就是为什么我很肯定我的问题有解决方案)...
TeXStudio 允许我将其括在注释之间%BEGIN_FOLD
,%END_FOLD
这样我就可以解决整个混乱局面。但是,我有两个顾虑:
%BEGIN_FOLD
默认情况下,和不会%END_FOLD
折叠,重新打开文件时会重新展开。此外,我不确定这是否是 TeXStudio 独有的功能。它会影响编译时间吗?我不知道编译器如何处理
\newcommand
s,但如果每次都必须重新定义并重新编译它们,我肯定还有改进的空间。
因此,我提出以下问题:
有没有办法将每 26 个命令块压缩为单个命令?
总之,我不想做这样的事情\bb{A}
,,\ms{A}
ETC也就是说,我不只是想要这些命令的别名。我愿意实现的是摆脱这些花括号,原因有二:
由于我已经使用这些命令几年了,肌肉记忆会出现问题。
输入
Alt Gr
+4
、Alt Gr
++
、继续Left
、输入字母并Right
再次继续需要相当长的时间:这就是我最初制作这些命令的原因。
我不是像你们中某些人那样的 LaTeX 专家,你们已经给了我很多帮助,也许我在尝试寻找除了“蛮力” 130 行之外的另一种方法时错过了一些东西……非常感谢你们的回复!
答案1
远远少于 130 行代码。
这个想法是在给定的范围内进行循环;我使用字母常量,因此,例如,A
对应于 63,但没有必要知道它。循环索引用 表示,##1
并将依次取字母的 ASCII 号;借助 ,\char_generate:nn
我们可以生成相应的字符。定义是“扩展的”,因此我们不需要扩展命令,只需在其前面加上 即可\exp_not:N
。
\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\definealphabet}{mmmm}
{% #1 = prefix, #2 = command, #3 = start, #4 = end
\int_step_inline:nnn { `#3 } { `#4 }
{
\cs_new_protected:cpx { #1 \char_generate:nn { ##1 }{ 11 } }
{
\exp_not:N #2 { \char_generate:nn { ##1 } { 11 } }
}
}
}
\ExplSyntaxOff
\definealphabet{bb}{\mathbb}{A}{Z}
\definealphabet{mc}{\mathcal}{A}{Z}
\definealphabet{mf}{\mathfrak}{A}{Z}
\definealphabet{mf}{\mathfrak}{a}{z}
\begin{document}
$\bbA+\mcB+\mfS+\mfz$
\end{document}
更通用的方法:
\documentclass{article}
\usepackage{amsmath,amsfonts}
\ExplSyntaxOn
\NewDocumentCommand{\definealphabet}{smmm}
{% #1 = star for lowercase , #2 = prefix, #3 = suffix, #4 = math alphabet
\IfBooleanTF { #1 }
{
\physicsstudent_definealphabet:nnnnn { #2 } { #3 } { `a } { `z } { #4 }
}
{
\physicsstudent_definealphabet:nnnnn { #2 } { #3 } { `A } { `Z } { #4 }
}
}
\msg_new:nnn { physicsstudent/definealphabet } { existing }
{
Command ~ '\exp_not:c { #1 #2 #3 }' ~ already ~ defined
}
\cs_new_protected:Nn \physicsstudent_definealphabet:nnnnn
{
\int_step_inline:nnn { #3 } { #4 }
{
\__physicsstudent_definealphabet:ennn { \char_generate:nn { ##1 } { 12 } } { #1 } { #2 } { #5 }
}
}
\cs_new_protected:Nn \__physicsstudent_definealphabet:nnnn
{
\cs_if_exist:cTF { #2 #1 #3 }
{
\msg_warning:nnnnn { physicsstudent/definealphabet } { existing } { #2 } { #1 } { #3 }
}
{
\cs_new_protected:cpn { #2 #1 #3 } { #4 { #1 } }
}
}
\cs_generate_variant:Nn \__physicsstudent_definealphabet:nnnn { e }
\ExplSyntaxOff
\let\Bbb\relax % after seeing the warning
\definealphabet{}{bb}{\mathbb}
\definealphabet{frak}{}{\mathfrak}
\definealphabet*{frak}{}{\mathfrak}
\begin{document}
$\Abb+\frakA-\frakb$
\end{document}
您可以指定前缀或后缀(或两者皆可)。使用 *-version,可以定义小写字母。
如果你漏掉了这一\let\Bbb\relax
行,你会收到警告
Package physicsstudent/definealphabet Warning: Command '\Bbb ' already defined
检查日志文件中是否存在此类情况,并决定命令能可以安全地重新定义(这\Bbb
是可能的,因为它只是为了与非常旧的文档兼容而定义的)或者前缀/后缀的改变是否更好。
答案2
该命令\DEFINEbbANDmcANDmsANDmfLOOP
旨在处理一个由一个标记组成的无界参数。它检查其参数的第一个标记的含义是否等于 -primitive 的含义\relax
。
如果是,它会通过 执行以下操作\@gobble
。
如果不是,它会假定该参数是一个表示⟨信⟩并通过执行以下操作\@firstofone
:
- 定义要扩展的宏
\bb⟨letter⟩
\mathbb{⟨letter⟩}
- 定义要扩展的宏
\mc⟨letter⟩
\mathcal{⟨letter⟩}
- 定义要扩展的宏
\ms⟨letter⟩
\mathscr{⟨letter⟩}
- 定义要扩展的宏
\mf⟨letter⟩
\mathfrakr{⟨letter⟩}
- 再次呼叫自己。
宏再次调用自身以将相同的操作应用于另一个参数的概念称为尾递归。
(为了定义宏,我实现了一个小辅助宏,\CmdName
其工作原理如下:
\CmdName⟨stuff without braces⟩{macroname}
→ ⟨stuff without braces⟩\macroname
。
例子:
\CmdName\newcommand*{foobar}...
→ \newcommand*\foobar...
。
\CmdName
当我没心情打字时我经常使用它\expandafter
。\csname..\endcsname
;-) )
\documentclass{article}
\makeatletter
\@ifdefinable\CmdName{\long\def\CmdName#1#{\romannumeral0\innerCmdName{#1}}}%
\newcommand\innerCmdName[2]{\expandafter\exchange\expandafter{\csname #2\endcsname}{ #1}}%
\newcommand\exchange[2]{#2#1}%
\newcommand\DEFINEbbANDmcANDmsANDmfLOOP[1]{%
\ifx\relax#1\expandafter\@gobble\else\expandafter\@firstofone\fi
{%
\CmdName\newcommand*{bb#1}{\mathbb{#1}}%
\CmdName\newcommand*{mc#1}{\mathcal{#1}}%
\CmdName\newcommand*{ms#1}{\mathscr{#1}}%
\CmdName\newcommand*{mf#1}{\mathfrak{#1}}%
\DEFINEbbANDmcANDmsANDmfLOOP
}%
}%
\makeatother
% Now for each of the letters define \bb<letter>, \mc<letter>, \ms<letter> and \mf<letter>:
\DEFINEbbANDmcANDmsANDmfLOOP abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\relax
\begin{document}
\show\bba
\show\mca
\show\msa
\show\mfa
\show\bbb
\show\mcb
\show\msb
\show\mfb
% .
% .
% .
% .
\show\bbY
\show\mcY
\show\msY
\show\mfY
\show\bbZ
\show\mcZ
\show\msZ
\show\mfZ
\end{document}
如果愿意,可以使用宏应用尾递归\Definealphabet
:
\documentclass{article}
\makeatletter
\newcommand\DEFINEALPHABETLOOP[3]{%
\ifx\relax#3\expandafter\@gobble\else\expandafter\@firstofone\fi
{\expandafter\newcommand\expandafter*\csname#1#3\endcsname{#2{#3}}%
\DEFINEALPHABETLOOP{#1}{#2}}%
}%
\newcommand\Definealphabet[2]{%
\DEFINEALPHABETLOOP{#1}{#2}abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\relax
}%
\makeatother
\Definealphabet{bb}{\mathbb}
\Definealphabet{mc}{\mathcal}
\Definealphabet{ms}{\mathscr}
\Definealphabet{mf}{\mathfrak}
\begin{document}
\show\bba
% ...
\show\bbz
\show\mca
% ...
\show\mcz
\show\msa
% ...
\show\msz
\show\mfa
% ...
\show\mfz
\end{document}
如果你需要 TeX-⟨数字⟩-quantity 表示 TeX 内部字符表示方案中字符的字符代码,您可以使用字母常量。
例如,`A
和都`\A
表示字符的字符代码A
。
后者不是“ \lowercase
-proof”。
在宏编程上下文中,后者可能无法证明后面的控制序列标记`
。\outer
还要
注意,TeX 使用字母常量的最后一个标记来扫描一个可选空格。
因此,如果您愿意,您也可以实现尾部递归循环,其中与/ -trickery\csname..\endcsname
相结合以循环遍历字母表,并且您可以为要调用的 math-alphabet-command 指定斜杠分隔的短语,并为命令名称指定定义字母前的前缀和字母后后的后缀:\lccode
\lowercase
\documentclass{article}
\makeatletter
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\@ifdefinable\SlashFirstOfThree{\long\def\SlashFirstOfThree#1/#2/#3/{#1}}%
\@ifdefinable\SlashArgBetweenSecondAndThirdOfThree{\long\def\SlashArgBetweenSecondAndThirdOfThree#1#2/#3/#4/{#3#1#4}}%
\newcommand\DefineAlphabetsLoop[1]{\DefineAlphabetsLoopInner{`\A}#1\relax}%
\newcommand\DefineAlphabetsLoopInner[2]{%
% #1 - character-code of character wherefore macro is to be defined; #2 - slash-separated triple of phrases:
% of pattern
% <math-alphabet-macro to call>/<prefix before alphabet-letter of name of macro to define>/<prefix after alphabet-letter of name of macro to define>
\ifx\relax#2\expandafter\@gobble\else\expandafter\@firstofone\fi{%
\ifnum#1>\@firstofone{`\z} \expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
%\@ifundefined{\SlashArgBetweenSecondAndThirdOfThree{z}#2/}%
{%
\begingroup
\lccode`\m=#1\relax
\lowercase\expandafter{\expandafter\PassFirstToSecond\expandafter{\SlashFirstOfThree#2/{m}}}%
{%
\lowercase{\PassFirstToSecond{m}}%
{\endgroup\expandafter\newcommand\expandafter*\csname\SlashArgBetweenSecondAndThirdOfThree}#2/\endcsname
}%
\expandafter\DefineAlphabetsLoopInner\expandafter{\the\numexpr\ifnum#1=`\Z`\a\else(#1)+1\fi\relax}{#2}%
}{%
\DefineAlphabetsLoopInner{`\A}%
}%
}%
}%
\makeatother
\begin{document}
%-------------------------------------------------------------------------------------
% Only prefix:
\DefineAlphabetsLoop{{\mathbb/bb/}{\mathcal/mc/}{\mathscr/ms/}{\mathfrak/mf/}}%
\show\bbA \show\mcA \show\msA \show\mfA
\show\bbB \show\mcB \show\msB \show\mfB
\show\bbY \show\mcY \show\msY \show\mfY
\show\bbZ \show\mcZ \show\msZ \show\mfZ
% .
% .
% .
% .
\show\bba \show\mca \show\msa \show\mfa
\show\bbb \show\mcb \show\msb \show\mfb
\show\bby \show\mcy \show\msy \show\mfy
\show\bbz \show\mcz \show\msz \show\mfz
%-------------------------------------------------------------------------------------
% Only postfix:
% Of course you get: ! LaTeX Error: Command \bbb already defined.
% That's because \bbb was defined by the prevous loop.
\DefineAlphabetsLoop{{\mathbb//bb}{\mathcal//mc}{\mathscr//ms}{\mathfrak//mf}}%
\show\Abb \show\Amc \show\Ams \show\Amf
\show\Bbb \show\Bmc \show\Bms \show\Bmf
\show\Ybb \show\Ymc \show\Yms \show\Ymf
\show\Zbb \show\Zmc \show\Zms \show\Zmf
% .
% .
% .
% .
\show\abb \show\amc \show\ams \show\amf
\show\bbb \show\bmc \show\bms \show\bmf
\show\ybb \show\ymc \show\yms \show\ymf
\show\zbb \show\zmc \show\zms \show\zmf
%-------------------------------------------------------------------------------------
% Both prefix and postfix:
\DefineAlphabetsLoop{{\mathbb/bb/bb}{\mathcal/mc/mc}{\mathscr/ms/ms}{\mathfrak/mf/mf}}%
\show\bbAbb \show\mcAmc \show\msAms \show\mfAmf
\show\bbBbb \show\mcBmc \show\msBms \show\mfBmf
\show\bbYbb \show\mcYmc \show\msYms \show\mfYmf
\show\bbZbb \show\mcZmc \show\msZms \show\mfZmf
% .
% .
% .
% .
\show\bbabb \show\mcamc \show\msams \show\mfamf
\show\bbbbb \show\mcbmc \show\msbms \show\mfbmf
\show\bbybb \show\mcymc \show\msyms \show\mfymf
\show\bbzbb \show\mczmc \show\mszms \show\mfzmf
%-------------------------------------------------------------------------------------
% Of course, instead of having three `\DefineAlphabetsLoop`, you could
% as well have done:
%
% \DefineAlphabetsLoop{%
% {\mathbb/bb/}{\mathcal/mc/}{\mathscr/ms/}{\mathfrak/mf/}%
% {\mathbb//bb}{\mathcal//mc}{\mathscr//ms}{\mathfrak//mf}%
% {\mathbb/bb/bb}{\mathcal/mc/mc}{\mathscr/ms/ms}{\mathfrak/mf/mf}%
% }%
\end{document}
一个稍微更通用的变体可能是:
\alphabetloop{<stuff>}
渐渐地: <stuff>{A}...<stuff>{Z}<stuff>{a}...<stuff>{z}
和
\LoopEachOverAlphabet{<stuff prefix>}{<stuff postfix>}{%
{<stuff 1>}%
{<stuff 2>}%
%...
{<stuff n>}%
}%
渐渐地
\alphabetloop{<stuff prefix><stuff 1><stuff postfix>}%
\alphabetloop{<stuff prefix><stuff 2><stuff postfix>}%
...
\alphabetloop{<stuff prefix><stuff n><stuff postfix>}%
,然后变成
<stuff prefix><stuff 1><stuff postfix>{A}...<stuff prefix><stuff 1><stuff postfix>{Z}<stuff prefix><stuff 1><stuff postfix>{a}...<stuff prefix><stuff 1><stuff postfix>{z}%
<stuff prefix><stuff 2><stuff postfix>{A}...<stuff prefix><stuff 2><stuff postfix>{Z}<stuff prefix><stuff 2><stuff postfix>{a}...<stuff prefix><stuff 2><stuff postfix>{z}%
%...
<stuff prefix><stuff n><stuff postfix>{A}...<stuff prefix><stuff n><stuff postfix>{Z}<stuff prefix><stuff n><stuff postfix>{a}...<stuff prefix><stuff n><stuff postfix>{z}%
。
\documentclass{article}
\makeatletter
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\newcommand\alphabetloop{\alphabetloopinner{`\A}}%
\newcommand\alphabetloopinner[2]{%
\ifnum#1>\@firstofone{`\z} \expandafter\@gobble\else\expandafter\@firstofone\fi
{%
\begingroup
\lccode`\m=#1\relax
\lowercase{\PassFirstToSecond{m}}{\endgroup#2}%
\expandafter\alphabetloopinner\expandafter{\the\numexpr\ifnum#1=`\Z`\a\else(#1)+1\fi\relax}{#2}%
}%
}%
\newcommand\LoopEachOverAlphabet[3]{\LoopEachOverAlphabetInner{#1}{#2}#3\relax}%
\newcommand\LoopEachOverAlphabetInner[3]{%
\ifx\relax#3\expandafter\@gobble\else\expandafter\@firstofone\fi{%
\alphabetloop{#1#3#2}%
\LoopEachOverAlphabetInner{#1}{#2}%
}%
}%
\@ifdefinable\definealphabetmacro{%
\long\def\definealphabetmacro#1/#2/#3/#4{\expandafter\newcommand\expandafter*\csname #2#4#3\endcsname{#1{#4}}}%
}%
\newcommand\DefineAlphabetMacros{%
\LoopEachOverAlphabet{\definealphabetmacro}{/}%
}%
\makeatother
\newcommand\showalphabetmacro[3]{%
\expandafter\show\csname #1#3#2\endcsname
}%
\begin{document}
%-------------------------------------------------------------------------------------
% Only prefix:
\DefineAlphabetMacros{{\mathbb/bb/}{\mathcal/mc/}{\mathscr/ms/}{\mathfrak/mf/}}%
%-------------------------------------------------------------------------------------
% Only postfix:
% Of course you get: ! LaTeX Error: Command \bbb already defined.
% That's because \bbb was defined by the prevous loop.
\DefineAlphabetMacros{{\mathbb//bb}{\mathcal//mc}{\mathscr//ms}{\mathfrak//mf}}%
%-------------------------------------------------------------------------------------
% Both prefix and postfix:
\DefineAlphabetMacros{{\mathbb/bb/bb}{\mathcal/mc/mc}{\mathscr/ms/ms}{\mathfrak/mf/mf}}%
%-------------------------------------------------------------------------------------
% Of course, instead of having three `\DefineAlphabetsLoop`, you could
% as well have done:
%
% \DefineAlphabetMacros{%
% {\mathbb/bb/}{\mathcal/mc/}{\mathscr/ms/}{\mathfrak/mf/}%
% {\mathbb//bb}{\mathcal//mc}{\mathscr//ms}{\mathfrak//mf}%
% {\mathbb/bb/bb}{\mathcal/mc/mc}{\mathscr/ms/ms}{\mathfrak/mf/mf}%
% }%
% This does \show 12*52 = 624 times. \bbb is shown twice:
\def\scratch{0}
\LoopEachOverAlphabet{%
\edef\scratch{\the\numexpr\scratch+1\relax}%
\message{^^JIteration \scratch:^^J}%
\showalphabetmacro
}{}{%
{{bb}{}} {{mc}{}} {{ms}{}} {{mf}{}}
{{}{bb}} {{}{mc}} {{}{ms}} {{}{mf}}
{{bb}{bb}} {{mc}{mc}} {{ms}{ms}} {{mf}{mf}}
}%
\end{document}