如何检查参数的值是否为数字?

如何检查参数的值是否为数字?

我有一个带参数的命令。我想检查其值是否为正数并根据该值执行操作。

\newcommand{\mycommand}[1]{
    \ifnum#1>0%
        %some actions
    \fi
}

但是当参数的值不是数字时,我会收到错误,例如:

\mycommand{*}

我如何检查 #1 的值是否是数字?

答案1

更新:

由于看起来包\IfInteger中的将xtring空字符串视为整数(空字符串{}是可以的,但不是{ }),我定义了一个修改后的宏\IsInteger来处理这种情况:

在此处输入图片描述

\documentclass{article}

\newcommand*{\IsInteger}[3]{%
    \IfStrEq{#1}{ }{%
        #3% is a blank string
    }{%
        \IfInteger{#1}{#2}{#3}%
    }%
}%
\usepackage{xstring}
\begin{document}
$2$ is \IsInteger{2}{an integer}{not an integer}\par
$2.0$ is \IsInteger{2.0}{an integer}{not an integer}

$-7$ is \IsInteger{-7}{an integer}{not an integer}\par
$-7.0$ is \IsInteger{-7.0}{an integer}{not an integer}

$2.1$ is \IsInteger{2.1}{an integer}{not an integer}\par
$-7.1$ is \IsInteger{-7.1}{an integer}{not an integer}

a is \IsInteger{a}{an integer}{not an integer}

Empty String is \IsInteger{}{an integer}{not an integer}\par
Blank String is \IsInteger{       }{an integer}{not an integer}
\end{document}

您可以IfInteger使用包裹xstring测试它是否是一个整数:

在此处输入图片描述

还有\IfDecimal类似工作原理的。

\documentclass{article}
\usepackage{xstring}
\begin{document}
2 is \IfInteger{2}{integer}{not an integer}

a is \IfInteger{a}{integer}{not an integer}
\end{document}

答案2

这主要取决于预期的输入以及您想要使用该命令的上下文。

如果你的预期输入是数字或者没有从数字开始,然后

\newcommand{\mycommand}[1]{%
  \ifnum0<0#1\relax
    #1 is a positive number%
  \else
    #1 is not a positive number%
  \fi}

会这样做。例如,\mycommand{42}将进行比较,0<042结果为真;相反,使用\mycommand{*}TeX 时,将看到\ifnum0<0*\relax并测试0<0,结果为假,因此*将被忽略为“真文本”的一部分。此外,来自的测试\mycommand{0}将评估为假。

另一方面,\mycommand{1x}测试将评估为真并给出错误的结果。

另一种可扩展的方式是

\def\mycommand#1{%
  \if\relax\detokenize\expandafter{\romannumeral-0#1}\relax
    #1 is a number%
  \else
    #1 is not a number%
  \fi
}

\mycommand{0}测试结果为真。这里\mycommand{1x}会回答这1x不是一个数字。

但是,论点不应该包含“危险”的内容:\mycommand{\textbf{x}}将会惨遭失败。

不可扩展的测试可以是

\makeatletter
\def\mycommand#1{%
  \afterassignment\get@args\count@=0#1\hfuzz#1\hfuzz}
\def\get@args#1\hfuzz#2\hfuzz{%
  \if\relax\detokenize{#1}\relax
    #2 is a number%
  \else
    #2 is not a number%
  \fi
}
\makeatother

这也适用于诸如\mycommand{\textbf{1}}(测试结果为假)的输入。

答案3

这是一个可扩展的解决方案,甚至可以接受未定义的控制序列。诚然,它很复杂。

中的一些命令期权为了提高速度和进行实验,这里重新定义了包。

\documentclass[a4paper]{article}
\usepackage{catoptions}
\makeatletter
\new@def\cptifdef#1{%
  \cptifblank{#1}{%
    \@secondoftwo
  }{%
    \csname @\ifx#1\@undefined second\else
    \ifx#1\relax second\else first\fi\fi oftwo\endcsname
  }%
}
\new@def\cptifundef#1{\cptifdef{#1}\@secondoftwo\@firstoftwo}
\new@def\cptifleftbraced#1{%
  \cptifblank{#1}{%
    \@secondoftwo
  }{%
    \csname @\if\expandafter\cpt@car\detokenize{#1}\car@nil
      \expandafter\cpt@car\string{\car@nil\ifnum0=`}\fi
      first\else second\fi oftwo\endcsname
  }%
}
\new@def\cptifxpandable#1{%
  \cptifleftbraced{#1}{%
    \@secondoftwo
  }{%
    \expandafter\ifx\noexpand#1#1%
      \expandafter\@secondoftwo
    \else
      \expandafter\@firstoftwo
    \fi
  }%
}
\newcommand\cpttwooftwo[2]{#1#2}
\newcommand\cptifblank[1]{%
  \expandafter\ifx\expandafter\noboundary\@gobble#1.\noboundary
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\newcommand\cptifcmdeq[2]{%
  \ifx#1#2\cpt@quark
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\long\def\cptifsolo#1{%
  \if0\pdfstrcmp{\detokenize\expandafter
    {\cpttwooftwo#1{}{}}}{\detokenize{#1{}}}%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\new@def\cptxpand#1{%
  \romannumeral-`\q\cptifblank{#1}{\space}{\cpt@xpand#1\xpand}%
}
\def\cpt@xpand#1#2\xpand{%
  \cptifsolo{#1}{%
    \cptifundef{#1}{%
      \cpt@@xpand{#2}{\noexpand#1}%
    }{%
      \cptifxpandable{#1}{%
        \cpt@@xpand{#2}{\expandafter\cpt@xpand#1\xpand}%
      }{%
        \cpt@@xpand{#2}{\noexpand#1}%
      }%
    }%
  }{%
    \cpt@@xpand{#2}{\cpt@xpand#1\xpand}%
  }%
}
\def\cpt@@xpand#1{%
  \expandafter\cptswap\expandafter{\romannumeral-`\q
  \cptifblank{#1}{\space}{\cpt@xpand#1\xpand}}%
}
\def\ifinteger#1{%
  \if\cptifblank{#1}{1}{\expandafter\ifinteger@a\romannumeral-`\q
  \cpt@xpand#1\xpand\cpt@nnil}00%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\def\ifinteger@a#1{%
  \cptifcmdeq#1\cpt@nnil{}{%
    \ifinteger@b#1\cpt@nil0123456789\cpt@nnil
  }%
}
\def\ifinteger@b#1\cpt@nil#2#3\cpt@nnil{%
  \expandafter\cptifcmdeq\cpt@car#1\car@nil#2{%
    \ifinteger@a
  }{%
    \cptifblank{#3}{%
      1\cpt@removetonnil
    }{%
      \ifinteger@b#1\cpt@nil#3\cpt@nnil
    }%
  }%
}

% Tests
\def\cmda{01}
\def\cmdb{xy}
\let\cmdc\undefined
\edef\cmdd{\ifinteger{\cmda}{True}{False}}
\edef\cmde{\ifinteger{\cmdc}{True}{False}}
\edef\cmdf{\ifinteger{\cmda\cmdb\cmdc}{True}{False}}
\show\cmdf

答案4

我知道,我“有点迟到了”,但这似乎效果不错:

\makeatletter
\def\mycommand#1{%
  \sbox\z@{\@tempcnta=0#1\relax}%
  \expandafter\ifdim\wd\z@>\z@\relax
    #1 is NOT an integer
  \else
    #1 is an integer
  \fi}
\makeatother

只要您尝试查找正整数(即计数器),而不是浮点数或负数,这就会有效。

相关内容