我一直不喜欢 TeX 语法的一点是,双上标或双下标会产生错误;如果只是简单地堆叠它们,我会觉得更自然。所以为了好玩,我决定尝试改变它,这样 ega^2^3
就等同于a^{23}
。唯一的问题是,它似乎不适用于素数或扩展为 的命令^{-1}
,见下文。因此,以下 MWE 会产生错误。可以以某种方式修复它吗?(我认为不能。)
\documentclass{article}
\catcode`^=\active
\catcode`_=\active
\makeatletter
\let\old@sp=\sp
\let\old@sb=\sb
\NewDocumentCommand{\@stack@index}{mme{^_}}
{%
\IfValueTF{#3}{%
\IfValueTF{#4}{%
\@stack@index{#1#3}{#2#4}%
}%
{%
\@stack@index{#1#3}{#2}%
}%
}%
{%
\IfValueTF{#4}{%
\@stack@index{#1}{#2#4}%
}%
{%
\old@sp{#1}\old@sb{#2}%
}%
}%
}
\def^#1{\@stack@index{#1}{}}
\def\sp#1{\@stack@index{#1}{}}
\def_#1{\@stack@index{}{#1}}
\def\sb#1{\@stack@index{}{#1}}
\makeatother
\begin{document}
\( x^2^3_2_{222}^{423} \)
\( x'^{-1} \)
\newcommand\inv{^{-1}}
\( x'\inv \)
\( x^2\inv \)
\end{document}
答案1
这里我使用tokcycle
伪环境\subsup...\endsubsup
来实现目标。它可以覆盖文档的任意部分,只要它不包含 catcode 更改标记(例如 verbatim)。
逻辑如下:
标记循环依次检查输入流中的每个标记。在几乎所有情况下,它都只是在
\cytoks
标记列表中累积。但是,对于“字符”标记,它会执行以下测试:\testss
初始化,然后测试#1
脚本 catcodes。如果失败,它将执行#2
(将测试的标记放入\cytoks
)。如果成功,它将调用...\accumsup
或分别\accumsub
将下一个标记累积到\thesups
或中\thesubs
。然后转到...\contss
窥视并查看下一个标记是否属于脚本 catcode。如果是,则丢弃窥视的脚本标记并返回步骤 2。如果不是,则转到...\closess
将 的内容设置\thesups
为上标,将 的内容设置\thesubs
为下标(通过将它们添加到\cytoks
)。然后退出并返回到令牌循环。在环境的结论部分,
\cytoks
进行了排版。
请注意,此过程仅适用于子/上标的外部嵌套。内部嵌套以正常方式运行。例如,在我的 MWE 中,我无法使用z_i_j
代替,z_i
因为z_i
嵌套在\sum
的脚本中。我必须使用常规的z_{ij}
。
妇女权利委员会:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle}[2021-05-27]
\newcommand\testss[2]{%
\def\thesups{}%
\def\thesubs{}%
\tctestifcatnx ^#1{\accumsup}{%
\tctestifcatnx _#1{\accumsub}{#2}}%
}
\newcommand\contss{%
\tcpeek\next
\tctestifcatnx ^\next{\tcpop\discard\accumsup}{%
\tctestifcatnx _\next{\tcpop\discard\accumsub}{\closess}}%
}
\newcommand\closess{%
\ifx\empty\thesups\else
\addcytoks{^}\groupedcytoks{\addcytoks[1]{\thesups}}\fi
\ifx\empty\thesubs\else
\addcytoks{_}\groupedcytoks{\addcytoks[1]{\thesubs}}\fi
}
\newcommand\accumsup{\tcpopappto\thesups\contss}
\newcommand\accumsub{\tcpopappto\thesubs\contss}
\tokcycleenvironment\subsup
{\testss{##1}{\addcytoks{##1}}}
{\processtoks{##1}}
{\addcytoks{##1}}
{\addcytoks{##1}}
\begin{document}
\subsup
\section{No problem}
$\sum_{3\sqrt{z_i}}^4_x^{xy^2}rs$ And now display style
\[
\sum_{3\sqrt{z_i}}^4_x^{xy^2}rs
\]
\section{Still no problem}
Wow! $\sum_{3\sqrt{z_i}}^4_x^{xy^2}rs$ And again display style
\begin{equation}
\sum_{3\sqrt{z_i}}^4_x^{xy^2}rs
\end{equation}
\endsubsup
\end{document}
现在上面的版本确实不是拦截扩展到脚本的宏。尝试扩展每一个遇到宏,正在搜索脚本 catcode。
但是,如果某人心中有一个特定的宏,其替换文本是脚本,例如\inv
,定义为^{-1}
,或\pushforward
,定义为,则可以执行测试以拦截此类宏并在输入流中替换它们的替换文本。对于脚本素数_{*}
的特殊情况也是如此。'
以下 MWE 需要更改\subsup
tokcycle 环境以及宏以执行和宏\contss
的额外拦截。宏需要更改以拦截script-prime 标记。\inv
\pushforward
\contss
'
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle}[2021-05-27]
\newcommand\testss[2]{%
\def\thesups{}%
\def\thesubs{}%
\tctestifcatnx ^#1{\accumsup}{%
\tctestifcatnx _#1{\accumsub}{#2}}%
}
\newcommand\contss{%
\tcpeek\next
\ifx\inv\next
\tcpop\discard\tcpush\inv\contss
\else
\ifx'\next
\tcpop\discard\tcpush{\empty\prime}\accumsup
\else
\ifx\pushforward\next
\tcpop\discard\tcpush\pushforward\contss
\else
\tctestifcatnx ^\next{\tcpop\discard\accumsup}{%
\tctestifcatnx _\next{\tcpop\discard\accumsub}{\closess}}%
\fi
\fi
\fi
}
\newcommand\closess{%
\ifx\empty\thesups\else
\addcytoks{^}\groupedcytoks{\addcytoks[1]{\thesups}}\fi
\ifx\empty\thesubs\else
\addcytoks{_}\groupedcytoks{\addcytoks[1]{\thesubs}}\fi
}
\newcommand\accumsup{\tcpopappto\thesups\contss}
\newcommand\accumsub{\tcpopappto\thesubs\contss}
\tokcycleenvironment\subsup
{\testss{##1}{\addcytoks{##1}}}
{\processtoks{##1}}
{\tctestifx{\inv##1}{\tcpush\inv}{%
\tctestifx{\pushforward##1}{\tcpush\pushforward}{%
\addcytoks{##1}}}}
{\addcytoks{##1}}
\newcommand\inv{^{-1}}
\newcommand\pushforward{_{*}}
\begin{document}
\subsup
\begin{equation}x\inv_{3z}^{xy^2}\pushforward\end{equation}
\begin{equation}x_{3z}\inv\pushforward^{xy^2}\end{equation}
\begin{equation}x_{3z}\pushforward\inv^{xy^2}\end{equation}
\begin{equation}x\pushforward_{3z}^{xy^2}\inv\end{equation}
\begin{equation}
x'_1\pushforward'_2\pushforward'_3\pushforward'
\end{equation}
\[
a'\inv \quad x^2^3_2_{222}^{423}
\]
\endsubsup
\end{document}
正如 David 在对 OP 的评论中指出的那样,上述方法不支持非标准但经常使用的x^\frac12
和语法x^\mathrm{y}
。但是,即使这样也可以通过对\accumsup
和进行适当的重新定义来适应\accumsub
。
为了证明这一点,这里有一个支持使用x^\frac12
和的版本x^\mathrm{y}
。
\documentclass{article}
\usepackage{tokcycle}[2021-05-27]
\makeatletter% BUG FIX, REPAIRED IN tokcycle 1.41 2021-06-25
\def\tcpopliteralappto#1{\tcpopliteral\@@tmp\tcappto#1from\@@tmp}
\makeatother
\newcommand\testss[2]{%
\def\thesups{}%
\def\thesubs{}%
\tctestifcatnx ^#1{\accumsup}{%
\tctestifcatnx _#1{\accumsub}{#2}}%
}
\newcommand\contss{%
\tcpeek\next
\ifx\inv\next
\tcpop\discard\tcpush\inv\contss
\else
\ifx'\next
\tcpop\discard\tcpush{\empty\prime}\accumsup
\else
\ifx\pushforward\next
\tcpop\discard\tcpush\pushforward\contss
\else
\tctestifcatnx ^\next{\tcpop\discard\accumsup}{%
\tctestifcatnx _\next{\tcpop\discard\accumsub}{\closess}}%
\fi
\fi
\fi
}
\newcommand\closess{%
\ifx\empty\thesups\else
\addcytoks{^}\groupedcytoks{\addcytoks[1]{\thesups}}\fi
\ifx\empty\thesubs\else
\addcytoks{_}\groupedcytoks{\addcytoks[1]{\thesubs}}\fi
}
\newcommand\accumsup{\tcpeek\next\tcpopappto\thesups\chek{\thesups}\contss}
\newcommand\accumsub{\tcpeek\next\tcpopappto\thesubs\chek{\thesubs}\contss}
\newcommand\chek[1]{\ifx\frac\next\popX{#1}\popX{#1}\else
\ifx\mathrm\next\popX{#1}\fi\fi}
\newcommand\popX[1]{\tcpopliteralappto#1}
\tokcycleenvironment\subsup
{\testss{##1}{\addcytoks{##1}}}
{\processtoks{##1}}
{\tctestifx{\inv##1}{\tcpush\inv}{%
\tctestifx{\pushforward##1}{\tcpush\pushforward}{%
\addcytoks{##1}}}}
{\addcytoks{##1}}
\newcommand\inv{^{-1}}
\newcommand\pushforward{_{*}}
\begin{document}
\subsup
\[ x\inv^3_2_{22^22}^{423}^\frac12_\mathrm{xy}\pushforward \]
\endsubsup
\end{document}
答案2
我其实很久以前就这么做了。我写了一个命令\@stickysup
,允许我(在将其设置为等于该命令之后^
)\let
写入a^1^2^3_4
并获取
(实际上我只会在特定的宏中使用它而不是替换的含义^
。)
由于当时我需要在课堂上使用大量张量符号,因此我更进一步,实现了一个命令,可以让我编写a^1^2^3_4^5_6_7
并获取
我在下面发布了相关代码供您检查。我无法保证这在任何情况下都是安全的,而且我已经很长时间没有看过这段代码了,所以我希望没有关于它的详细问题 ;-)。基本思想与'
纯 TeX 相同。
\documentclass{article}
% A sticky superscript command (several of these can follow each other).
\makeatletter
\def\@stickysup#1{^\bgroup#1\@stickysup@glue}
\def\@stickysup@glue{\futurelet\@let@token\@stickysup@react}
\def\@stickysup@react{%
\ifx\@stickysup\@let@token
\expandafter\@stickysup@mergestickysup
\else
\ifx^\@let@token
\expandafter\expandafter\expandafter\@stickysup@mergesup
\else
\ifx'\@let@token
\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\@stickysup@mergeprime
\else
\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\@stickysup@end
\fi
\fi
\fi
}
\def\@stickysup@mergestickysup#1#2{#2\@stickysup@glue}
\def\@stickysup@mergesup#1#2{#2\egroup}
\def\@stickysup@mergeprime#1{\prime\@stickysup@glue}
\def\@stickysup@end{\egroup}
{\catcode`'\active\gdef'{\@stickysup\prime}}
\makeatother
% add switches for switching between normal and tensor-like sub- and superscripts
% \tensorscripts[<base>] switches on, \notensorscripts switches off.
% \tensor{<base>}{<scripts>} typesets only one tensor (like the {tensor} package)
% \tens{<base>} typesets only one tensor, but without braces around the scripts.
% \notens turns tensorscripts off for one time, but leaves scripts sticky.
% \crippletensorscripts makes _ and ^ not active, but doesn't revert any of the other changes
% (for use when a \label contains _).
\makeatletter
\NewDocumentCommand\tensorscripts{O{}}{%
\let\@sub_\let\@sup^%
\def\@tensorscript@separator{{\vphantom{#1}}}%
\catcode`_=\active\catcode`^=\active
\@tensorscript@activation
}
{\catcode`_=\active\catcode`^=\active
\gdef\@tensorscript@activation{%
\let_\@tensorsub
\let^\@tensorsup
\let\@stickysup@end\@tensorscript@end
}%
}
\def\crippletensorscripts{%
\catcode`_=8\catcode`^=7%
}
\def\tensor#1{\begingroup\tensorscripts[#1]#1\@tensor@secondarg}
\def\@tensor@secondarg#1{#1\endgroup}
\def\tens#1{\begingroup\tensorscripts[#1]\def\@tensorscript@veryend{\endgroup}#1}
\def\notens{\begingroup\tensorscripts\def\@tensorscript@separator{\unskip}\def\@tensorscript@veryend{\endgroup}}
\def\@add@tensorscriptcmd#1{%
\expandafter\def\csname @tensor#1\endcsname##1{%
\csname @#1\endcsname
\bgroup
\expandafter\let\expandafter\@current@tensorscript@cmd\csname @tensor#1\endcsname
##1%
\@tensorscript@glue
}%
}
\@add@tensorscriptcmd{sub}
\@add@tensorscriptcmd{sup}
\def\@tensorscript@glue{\futurelet\@tensorscript@lettoken\@tensorscript@react}
\def\@tensorscript@react{%
\ifx\@current@tensorscript@cmd\@tensorscript@lettoken
\expandafter\@tensorscript@merge
\else
\expandafter\@tensorscript@end
\fi
}
\def\@tensorscript@merge#1#2{#2\@tensorscript@glue}
\def\@tensorscript@end{\egroup\futurelet\@tensorscript@lettoken\@tensorscript@separate}
\def\@tensorscript@separate{%
\ifx\@tensorsub\@tensorscript@lettoken
\!\@tensorscript@separator
\else
\ifx\@tensorsup\@tensorscript@lettoken
\@tensorscript@separator
\else
\@tensorscript@veryend
\fi
\fi
}
\def\@tensorscript@veryend{}
\makeatother
\begin{document}
\begingroup\makeatletter
\catcode`^=\active
\let^\@stickysup
\[
a^1^2^3_4
\]
\endgroup
\[
\tensorscripts
a^1^2^3_4^5_6_7
\]
\end{document}