问题的新版本
如何以稳健的方式检测命令后面是否有下标?
我正在使用\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
然后再用\detokenize
eTeX 原语来做这件事,以确保后面的两个标记都属于第 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}