我有一个带参数的命令。我想检查其值是否为正数并根据该值执行操作。
\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
只要您尝试查找正整数(即计数器),而不是浮点数或负数,这就会有效。