使索引可堆叠

使索引可堆叠

我一直不喜欢 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)。

逻辑如下:

  1. 标记循环依次检查输入流中的每个标记。在几乎所有情况下,它都只是在\cytoks标记列表中累积。但是,对于“字符”标记,它会执行以下测试:

  2. \testss初始化,然后测试#1脚本 catcodes。如果失败,它将执行#2(将测试的标记放入\cytoks)。如果成功,它将调用...

  3. \accumsup或分别\accumsub将下一个标记累积到\thesups或中\thesubs。然后转到...

  4. \contss窥视并查看下一个标记是否属于脚本 catcode。如果是,则丢弃窥视的脚本标记并返回步骤 2。如果不是,则转到...

  5. \closess将 的内容设置\thesups为上标,将 的内容设置\thesubs为下标(通过将它们添加到\cytoks)。然后退出并返回到令牌循环。

  6. 在环境的结论部分,\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 需要更改\subsuptokcycle 环境以及宏以执行和宏\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}

相关内容