检测宏参数是否只有一个符号

检测宏参数是否只有一个符号

我使用一个小助手定义了一堆函数(或者运算符,如果你愿意的话)\parens,它可以根据需要添加括号:

\newcommand{\parens}[1]{
  \ifthenelse{\equal{#1}{}}{}{(#1)}
}

\newcommand{\fv}[1]{\text{fv}\parens{#1}}

这样,我不仅可以写\fv{e}“fv(e)”,还可以写\fv{} \colon Expr \to Var“fv : Expr → Var”。

从理论上讲,如果参数是一个符号,即,我通常会省略括号,fv e但仍然如此fv (e₁ e₂)

如果参数计算结果为单个符号,我该如何增强我的\parens宏以避免添加括号?

它不必是完美的,并且可能会因添加不必要的括号而犯错误。

以下是可供尝试的 MWE:

\documentclass{article}
\usepackage{amsmath}
\usepackage{ifthen}

\newcommand{\parens}[1]{
  \ifthenelse{\equal{#1}{}}{}{(#1)}
}
\newcommand{\fv}[1]{\text{fv}\parens{#1}}

\begin{document}
Has no parentheses: $\fv{}$.

Should have no parentheses: $\fv{e}$, $\fv{\alpha}$.

Should have parentheses: $\fv{e_1 + e_2}$, $\fv{e_1+e_2}$, $\fv{e_1, e_2, \ldots}$.

These also could have no parentheses: $\fv{e_1}$
(but that is probably too much to ask)

\end{document}

答案1

您可以使用正则表达式来执行此操作,在检查参数是否为空后:如果参数仅匹配一个标记或一个后跟一个下标的标记_,则不使用括号。

\documentclass{article}
\usepackage{amsmath}

\DeclareMathOperator{\fvop}{fv}

\ExplSyntaxOn

\NewDocumentCommand{\fv}{m}
 {
  \fvop
  \tl_if_blank:nF { #1 }
   {
    \regex_match:nnTF { \A . ( \_. | \_\{.*?\} )? \Z } { #1 }
     {
      #1
     }
     {
      (#1)
     }
   }
 }

\ExplSyntaxOff

\begin{document}

Has no parentheses: $\fv{}$.

Has no parentheses: $\fv{e_1}$.

Should have no parentheses: $\fv{e}$, $\fv{\alpha}$, $\fv{\alpha_{12}}$.

Should have parentheses: $\fv{e+f}$, $\fv{\alpha+\beta}$.

Should have parentheses: $\fv{e+f}$, $\fv{\alpha+\beta}$.

Should have parentheses: $\fv{e_1 + e_2}$, $\fv{e_1+e_2}$, $\fv{e_1, e_2, \ldots}$.

\end{document}

在此处输入图片描述

可以使用标准方法获得\fv*{...}强制自动扩展括号的扩展版本,而\fv[\big]{...}如果参数不是单个变量(您也可以使用\Big\bigg或),则使用更大的版本。\Biggmathtools

\documentclass{article}
\usepackage{amsmath,mathtools}

\DeclareMathOperator{\fvop}{fv}
\DeclarePairedDelimiter{\paren}{(}{)}

\ExplSyntaxOn

\NewDocumentCommand{\fv}{som}
 {
  \fvop
  \IfBlankF{#3}
   {
    \IfBooleanTF{#1}
     {
      \paren*{#3}
     }
     {
      \tl_if_blank:nF { #3 }
       {
        \regex_match:nnTF { \A . ( \_. | \_\{.*?\} )? \Z } { #3 }
         {
          #3
         }
       }
       {
        \IfNoValueTF{#2}{\paren{#3}}{\paren[#2]{#3}}
       }
     }
   }
 }

\ExplSyntaxOff

\begin{document}

Has no parentheses: $\fv{}$.

Has no parentheses: $\fv{e_1}$.

Should have no parentheses: $\fv{e}$, $\fv{\alpha}$, $\fv{\alpha_{12}}$.

Should have parentheses: $\fv{e+f}$, $\fv{\alpha+\beta}$.

Should have parentheses: $\fv{e+f}$, $\fv{\alpha+\beta}$.

Should have parentheses: $\fv{e_1 + e_2}$, $\fv{e_1+e_2}$, $\fv{e_1, e_2, \ldots}$.

Should have parentheses: $\fv*{\frac{e}{2}}$; compare with $\fv{\frac{e}{2}}$.
\[
\fv*{\frac{e}{2}}\quad\fv[\big]{\frac{e}{2}}\quad \fv*{e}\quad \fv[\big]{e}
\]

\end{document}

在此处输入图片描述

答案2

“单一符号”的概念有些模糊:我可以提出一个精确的测试来判断论证是否是一个单一的令牌

\documentclass{article}

\makeatletter

\newcommand*\IsOnlyOneToken[1]{%
  TT\fi
  \@IsOnlyOneToken#1\@@@
}
\@ifdefinable\@IsOnlyOneToken{\def\@IsOnlyOneToken#1#2\@@@{%
  \ifx\@empty#2\@empty
}}

\makeatother

\newcommand*{\clientCommand}[1]{%
  \mathrm{fv}%
  \if\IsOnlyOneToken{#1}%
    \,#1%
  \else
    \left(#1\right)%
  \fi
}



\begin{document}

Single token:
$\clientCommand{x}$,
$\clientCommand{\alpha}$.

Multiple tokens:
$\clientCommand{x+1}$,
$\clientCommand{x_{1}}$.

But an override is available:
$\clientCommand{{x_{1}}}$.

\end{document}

以下是输出(然而,这并不重要:您需要自己尝试一下……):

原始代码的输出

如您所见,如果您用一对额外的括号将参数括起来,测试会将参数视为单个标记。我认为这是一项功能,而不是错误。

编辑

\IsOnlyOneToken如果使用空参数调用,即包含以下参数,则上述代码将失败:标记。下面是解决方法:

\documentclass{article}

\makeatletter

\newcommand*\IsExactlyOneToken[1]{%
  TT\fi
  \ifx\@empty#1\@empty
    \expandafter\@EmptyCase
  \else
    \expandafter\@IsOnlyOneToken
  \fi
  #1\@@@
}
\@ifdefinable\@IsOnlyOneToken{\def\@IsOnlyOneToken#1#2\@@@{%
  \ifx\@empty#2\@empty
}}
\@ifdefinable\@EmptyCase{\def\@EmptyCase#1\@@@{% #1 for robustness
  \iffalse % since 0 != 1
}}

\makeatother

\newcommand*{\clientCommand}[1]{%
  \mathrm{fv}%
  \if\IsExactlyOneToken{#1}%
    \,#1%
  \else
    \nonscript\!\left(#1\right)%
  \fi
}



\begin{document}

Single token:
$\clientCommand{x}$,
$\clientCommand{\alpha}$.

Multiple tokens:
$\clientCommand{x+1}$,
$\clientCommand{x_{1}}$.

But an override is available:
$\clientCommand{{x_{1}}}$.

The bug has been corrected:
$\clientCommand{}$\ldots

\makeatletter
\ldots also for ``pathological'' cases:
$\clientCommand\@empty$, $\clientCommand{\@empty}$.
Override: $\clientCommand{{\@empty}}$.
\makeatother

\end{document}

输出:

修改后的代码输出

答案3

\IfSubStr可以xstring查找字符串之间的空白字符(也就是空格)。但是,这并不是万无一失的。

\documentclass{article}

\usepackage{xstring}
\usepackage{ifthen}
\usepackage{mathtools}

\newcommand{\parens}[1]{
  \ifthenelse{\equal{#1}{}}{}{(#1)}
}

\newcommand{\myarg}{e_{1} e_{2}}

\newcommand{\myotherarg}{e_{1} }


\newcommand{\fv}[1]{\text{fv}%
\IfSubStr{#1}{ }{%
\parens{#1}
}{\,#1}
}

\begin{document}
$\fv{v}$

$\fv{e_{1} e_{2}}$ 

$\fv{\myarg}$
$\fv{\myotherarg}$

\end{document}

答案4

仅基于 TeX 原语和简单的纯 TeX 宏的解决方案:

\newif\ifsingle
\def\issingle #1#2\iftrue{%
   \singlefalse
   \ifx&#2&\singletrue
   \else \issingleA #2\iftrue \issingleB #2\iftrue \singletrue
   \fi                \fi                  \fi
   \ifsingle
}
\def\issingleA #1#2\iftrue  {\ifx #1_}
\def\issingleB _#1#2\iftrue {\ifx&#2&}

\def\fv#1{\mathop{\rm fv}%
   \ifx&#1&% empty parameter, do nothig
   \else \issingle #1\iftrue {#1}\else ({#1})\fi 
   \fi
}

Has no parentheses: $\fv{}$.

Has no parentheses: $\fv{e_1}$.

Should have no parentheses: $\fv{e}$, $\fv{\alpha}$, $\fv{\alpha_{12}}$.

Should have parentheses: $\fv{e+f}$, $\fv{\alpha+\beta}$.

Should have parentheses: $\fv{e_1 + e_2}$, $\fv{e_1+e_2}$, $\fv{e_1, e_2, \ldots}$.

Should have parentheses: $\fv{e\over2}$.

相关内容