我正在撰写关于形式概念分析的硕士论文,我想为派生运算符创建一个自定义命令。它们是带有一些可选参数的上标箭头,看起来像这样:
\[ x^{\uparrow_i}, \quad a^{\downarrow^i} \]
因此,我第一次尝试将这些命令定义为:
\newcommand{\up}[1][]{^{\uparrow_{#1}}}
\newcommand{\down}[1][]{^{\downarrow^{#1}}}
然而,有些情况下这些操作符会一个接一个地被应用,并且
\[ x\up\down \]
会产生“双上标”错误。这有一个简单的解决方法,只需在表达式周围添加括号,如下所示:
\newcommand{\up}[1][]{{^{\uparrow_{#1}}}}
\newcommand{\down}[1][]{{^{\downarrow^{#1}}}}
这是我撰写论文时一直遵循的命令,但最近我发现,这个命令并不像我希望的那样有效。
\[ \Big( \bigvee p_i \Big)\up \]
此代码没有将箭头放置在应有的高度,就像此代码中一样
\[ \Big( \bigvee p_i \Big)^{\uparrow} \]
基本上,我想定义一个满足这两个要求的命令:我必须能够一个接一个地写入它们,并且它们应该在大符号旁边放置在正确的高度。
以下是我所拥有的 MWE:
\documentclass{article}
\newcommand{\up}[1][]{{^{\uparrow_{#1}}}}
\newcommand{\down}[1][]{{^{\downarrow^{#1}}}}
\begin{document}
Expected output:
\[
x^{\uparrow_i}, \quad x^{\uparrow_i\downarrow_j}, \quad \Big( \bigcup S \Big)^{\uparrow_i}
\]
How I want to write it:
\[
x\up[i], \quad x\up[i]\down[j], \quad \Big( \bigcup S \Big)\up[i]
\]
\end{document}
我的尝试:为了找到解决方案,我一直在互联网和论坛上寻找,并想出了一些办法(尽管我还没能让它发挥作用)。使用命令,我可以判断后面\@ifnextchar
是否有命令(或后面是否有命令),并据此进行操作。我得到的是以下内容:\down
\up
\up
\down
- 我在编写操作符时创建一个切换按钮
writing
(比如使用包etoolbox
),并将其设置为 false。 - 我创建了一个环境,
superscriptenv
以上面标的方式书写其内容。 - 当我启动
\up
或时\down
,如果writing
设置为false,我会启动上标环境,写下相应的箭头并切换writing
为true。 - 如果下一个命令是
down
或up
,则不执行任何其他操作。否则,结束上标环境并切换为writing
false。
下面是我编写的代码,仅带有up
运算符。
\documentclass{article}
\usepackage{etoolbox, environ}
\newtoggle{writing}
\togglefalse{writing}
\makeatletter
\NewEnviron{superscriptenv}{^{\BODY}}
\newcommand{\up}[1][]{
\iftoggle{writing}{}{%
\toggletrue{writing}%
\begin{superscriptenv}%
}%
\uparrow_{#1}
\@ifnextchar\up{}{%
\end{superscriptenv}%
\togglefalse{writingup}%
}
}
\begin{document}
\[
x\up[i], \quad x\up[I]\up[j], \quad \Big( \bigcup S \Big)\up[i]
\]
\end{document}
但是,由于“\begin{superscriptenv} 以 \end{document} 结尾”,因此无法编译。如果有人有任何想法,我将不胜感激。提前致谢!
答案1
您的想法几乎正确。
与使用切换和 Environ 相比,使用以下逻辑更容易:
- 每次
\up
或\down
启动时,按下它将添加到队列中的符号。 - 检查下一个标记是否是
\up
或\down
。 如果是,则不执行任何操作。 - 如果下一个标记既不是
\up
也不是\down
,则将整个队列带入,并重置队列。
\documentclass{article}
\makeatletter
\def\@sjmr@temp{}
\newcommand\up[1][]{%
\expandafter\def\expandafter\@sjmr@temp\expandafter{\@sjmr@temp\uparrow_{#1}}
\@ifnextchar\up{}{\@ifnextchar\down{}{^{\@sjmr@temp}\def\@sjmr@temp{}}}}
\newcommand\down[1][]{%
\expandafter\def\expandafter\@sjmr@temp\expandafter{\@sjmr@temp\downarrow_{#1}}
\@ifnextchar\up{}{\@ifnextchar\down{}{^{\@sjmr@temp}\def\@sjmr@temp{}}}}
\makeatother
\begin{document}
\[
x\up[i], \quad x\up[i]\down[j], \quad \Big( \bigcup S \Big)\up[i]\up[j]\down[k]
\]
\end{document}
答案2
您可以尝试以下宏:
\def\isnextchar#1#2#3{\def\tmp{#1{#2}{#3}}\futurelet\next\isnextcharA}
\def\isnextcharA{\expandafter\isnextcharB\tmp}
\def\isnextcharB#1#2#3{\ifx\next#1\afterfi{#2}\else\afterfi{#3}\fi}
\def\afterfi#1#2\fi{\fi#1}
\def\up{^\bgroup\upA.}
\def\upA#1{\isnextchar[{\updown\uparrow_}{\updown\uparrow_[]}}
\def\updown#1#2[#3]{#1#2{#3}\isnextchar\down{\downA}{\isnextchar\up{\upA}{\egroup}}}
\def\down{^\brgroup\downA.}
\def\downA#1{\isnextchar[{\updown\downarrow^}{\updown\downarrow^[]}}
Test:
$$ x\up[i]\down[j], \Bigr)\up[i]\down[j]\down[k] $$
主要思想是上标以 开头,然后扫描并打印文本,直到上标以或^\bgroup
以外的其他内容结束。然后以 结尾\up
\down
\egroup