检测命令后面是否跟着下标

检测命令后面是否跟着下标

问题的新版本

如何以稳健的方式检测命令后面是否有下标?

我正在使用\newcommand*{\command}[1]{\IfStrEq{#1}{_}{...}{...}},它可以工作,但它被一个名为 的包破坏了breqn。有没有更强大的方法可以在不使用包的情况下进行检测xstring,比如使用\@ifnextchar或其他内置命令?


问题的旧版本

我有一个打印概率的命令$\Prob{X=3}$,简单来说$P(X=3)$ 公式,有时我需要在 上使用长下标$P$,例如$${\operatorname*{P}}_{y\sim Y|X}{y=3|x=2}$$

公式

我想\Prob\Prob{X=3}和使用相同的宏\Prob_{y\sim Y|X}{y=3|x=2}来保持代码一致性。我写了一个部分可行的解决方案:

\usepackage{xstring}
\newcommand*{\Prob}[1]{\IfStrEq{#1}{_}{\ProbWithSub}{\ProbWithoutSub{#1}}}
\newcommand*{\ProbWithSub}[2]{{\operatorname*{P}_{#1}(#2)}}
\newcommand*{\ProbWithoutSub}[1]{{P(#1)}}

它似乎有效,但前提是命令是在之后定义的\begin{document}。否则我得到以下信息:公式

为什么会发生这种情况吗?我应该如何修复它以在之前定义它\begin{document}


最小工作示例

在制作一个最小工作示例时,我发现我的解决方案实际上是正确的,但被一个名为的包破坏了breqn。不过,我很好奇为什么它会中断,以及如何以稳健的方式检测下标。

\documentclass[conference]{IEEEtran}
\usepackage{amsmath}
\usepackage{xstring}
\usepackage{breqn} % Root of the problem

\newcommand{\custom}[1]{(#1)}

\newcommand*{\Prob}[1]{\IfStrEq{#1}{_}{\ProbWithSub}{\ProbWithoutSub{#1}}}
\newcommand*{\ProbWithSub}[2]{{\operatorname*{P}_{#1}\custom{#2}}}
\newcommand*{\ProbWithoutSub}[1]{{P\custom{#1}}}

\begin{document}
\newcommand*{\XProb}[1]{\IfStrEq{#1}{_}{\XProbWithSub}{\XProbWithoutSub{#1}}}
\newcommand*{\XProbWithSub}[2]{{\operatorname*{P}_{#1}\custom{#2}}}
\newcommand*{\XProbWithoutSub}[1]{{P\custom{#1}}}

These use Prob: $\Prob{X=3}$ and $\Prob_{y\sim Y|X}{y=3|x=5}$.

These use XProb: $\XProb{X=3}$ and $\XProb_{y\sim Y|X}{y=3|x=5}$.
\end{document}

姆韦

答案1

问题是一些 LaTeX 包将的 catcode 更改_为 12。您可以尝试:

\documentclass[conference]{IEEEtran}
\usepackage{breqn} % Root of the problem

\begin{document}
Catcode: \the\catcode`_ .
\end{document}

您将看到 12。如果删除\usepackage{breqn},您将看到 8。

因此,比较\IfStrEq{#1}{_}失败,因为第一个参数是_catcode 12,而第二个参数是_catcode 8。

我不懂 LaTeX 的\IfStrEq宏,所以我建议先用 TeX 原语,\ifx然后再用\detokenizeeTeX 原语来做这件事,以确保后面的两个标记都属于第 12 类。

\def\Prob #1{\expandafter\ifx\detokenize{_#1}\expandafter\ProbA \else \ProbB{#1}\fi}
\def\ProbA #1#2{\mathop{P{}}_{#1}(#2)}
\def\ProbB #1{P(#1)}

答案2

永远不要$$在 LaTeX 文档中使用(在某些情况下它可能用于定义环境,但那是专家的做法)。

只需定义

\DeclareMathOperator*{\Prob}{\mathnormal{P}}

完整代码:

\documentclass{article}
\usepackage{amsmath}

\DeclareMathOperator*{\Prob}{\mathnormal{P}}

\begin{document}

\begin{gather*}
\Prob(X=3) \\
\Prob_{y\sim Y\mid X}(y=3\mid x=2)
\end{gather*}

\end{document}

在此处输入图片描述

如果您想要吸收一个参数以便对其进行格式化,则可以使用e说明符\NewDocumentCommand

\documentclass{article}
\usepackage{amsmath}

\NewDocumentCommand{\Prob}{e{_}m}{%
  \operatorname*{\mathnormal{P}}%
  \IfValueT{#1}{_{#1}}%
  (#2)% other settings here
}

\begin{document}

\begin{gather*}
\Prob{X=3} \\
\Prob_{y\sim Y|X}{y=3\mid x=2}
\end{gather*}

\end{document}

答案3

您可以使用e参数类型。

在此处输入图片描述

\documentclass[conference]{IEEEtran}
\usepackage{amsmath}

\newcommand{\custom}[1]{(#1)}

\NewDocumentCommand\Prob{e{_}m}{\operatorname*{P}\IfNoValueF{#1}{_{#1}}\custom{#2}}

\begin{document}

These use Prob: $\Prob{X=3}$ and $\Prob_{y\sim Y|X}{y=3|x=5}$.


\end{document}

相关内容