检查字符串是否代表 PGF 的有效数字

检查字符串是否代表 PGF 的有效数字

我正在寻找一种可靠的方法来确定是否可以将字符串输入到 中\pgfmathprintnumber。我以前使用过包\IfDecimal中的xstring,它对于 和 等输入来说效果很好3.14。但是\pgfmathprintnumber无法处理将被 整理出来的科学记数法,\IfDecimal因为它认为它不是数字。

以下是 MWE:

\documentclass{article}

\usepackage{pgf}
\usepackage{xstring}

\begin{document}
    \def\testNum{3E+64}

    \IfDecimal{\testNum}{
        \pgfmathprintnumber[sci]{\testNum} is a number
    }{
        \pgfmathprintnumber[sci]{\testNum} is not a number
    }
\end{document}

正如您所看到的,该数字可以被正确识别,\pgfmathprintnumber但不能\IfDecimal

(我也尝试了包\DTLisnumerical中的命令datatool但它也不起作用)。

是否有人知道一个宏,它也可以检测科学符号为数字(最好是通过 PGF 本身进行验证 - 它会尝试用数学引擎解析字符串,但如果字符串不能解析为数字,它就会退出,而不是用错误杀死 LaTeX)?

答案1

好吧,我做了大量的网络研究,偶然发现这个问题上一个回答中有一个有趣的方法。此外,我发现这个帖子

从第一个链接问题中可以看出,有一个键/pgf/fpu/handlers/invalid number/.code定义当遇到错误的数字格式时的行为\pgfmathfloatparsenumber。引用手册:

如果在 \pgfmathfloatparsenumber 中解析了无效字符串,则会调用此命令键。您可以覆盖它以分配替换的 \pgfmathresult(浮点数!)。初始设置是生成错误消息。

从第二个问题中我发现,有一些标志可以指示解析的数字是否有效。所以我将它们两个结合起来得到

\documentclass{article}

\usepackage{pgf}
\usepgflibrary{fpu}

\newcommand{\isPGFNumber}[3]{% \isPGFNumber{<Number>}{<True>}{<False>}
    \begingroup
    \pgfkeys{/pgf/fpu/handlers/invalid number/.code={}}%
    \pgfmathfloatparsenumber{#1}%
    \global\pgfmathfloatgetflagstomacro\pgfmathresult\pgfFloatParseFlag%
    \endgroup
    \ifnum\pgfFloatParseFlag=3%
        #3%
    \else%
        #2%
    \fi%
}

\begin{document}
    \isPGFNumber{3}{T}{F}\\
    \isPGFNumber{3.23}{T}{F}\\
    \isPGFNumber{.3}{T}{F}\\
    \isPGFNumber{3E+12}{T}{F}\\
    \isPGFNumber{3e-8}{T}{F}\\
    \isPGFNumber{3z}{T}{F}\\
    \isPGFNumber{Is there a problem?}{T}{F}\\\\

    %\pgfmathfloatparsenumber{z}
\end{document}

\begingroup宏定义中的 and是\endgroup为了在调用宏后返回到正常的无效数字错误行为(可以通过取消注释文档中的最后一条语句来测试)。如您所见,即使以科学格式提供,它也能正确处理数字。

答案2

您可以使用正则表达式来完成此操作。

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx} % for the test

\ExplSyntaxOn

\prg_new_protected_conditional:Nnn \raven_if_fpnumber:n { T,F,TF }
 {
  \regex_match:nnTF { [eE] } { #1 }
   {% there is e or E
    \regex_match:nnTF
     {
      % optional sign,
      % optional integer part,
      % optional period,
      % optional fractional part,
      % one e or E
      % optional sign
      % mandatory integer
      \A
      [-+]?([0-9]+(\.[0-9]+)?|\.[0-9]+)
      [eE]{1}
      [-+]?[0-9]+
      \Z
     }
     { #1 } { \prg_return_true: } { \prg_return_false: }
   }
   {% no e nor E
    \regex_match:nnTF
     {
      \A
      [-+]?([0-9]+(\.[0-9]+)?|\.[0-9]+)
      \Z
     }
     { #1 } { \prg_return_true: } { \prg_return_false: }
   }
 }
\prg_generate_conditional_variant:Nnn \raven_if_fpnumber:n { x } { T,F,TF }

\NewDocumentCommand{\isfpnumberTF}{mmm}
 {
  \raven_if_fpnumber:xTF { #1 } { #2 } { #3 }
 }

\ExplSyntaxOff

% for the test
\newcommand{\test}[1]{%
  \texttt{\detokenize\expandafter{#1}}:
  \isfpnumberTF{#1}{\num{#1}}{``#1'' is not a number}%
}
\newcommand{\anumber}{3E+64}

\begin{document}

\test{\anumber}

\test{3}

\test{3.23}

\test{.3}

\test{3E+12}

\test{3e-8}

\test{3z}

\test{Is there a problem?}

\end{document}

在此处输入图片描述

答案3

以下内容基于我在其他地方实施的测试。我没有删除所有不必要的内容以使此答案有效,因此可能会添加不必要的内容。对论证中组的测试来自检查组作为参数(可扩展)

该测试应该是完全可扩展的。

\documentclass[]{article}

\makeatletter
\def\endMYifargument{\endMYifargument}
\newcommand\MYif@endMYifargument[1]% >>>
  {%
    \ifx\endMYifargument#1%
      \MYif@fiAa
    \else
      \MYif@fiBb
    \fi
  }% <<<
% MYif@fi macros >>>
\long\def\MYif@fiAa#1\fi#2#3{\fi#2}
\long\def\MYif@fiAb#1\fi#2#3{\fi#3}
\long\def\MYif@fiBa\fi#1#2{\fi#1}
\long\def\MYif@fiBb\fi#1#2{\fi#2}
\long\def\MYif@fiAy#1\fi#2{\fi#2}
\long\def\MYif@fiAn#1\fi#2{\fi}
\long\def\MYif@fiBy\fi#1{\fi#1}
\long\def\MYif@fiBn\fi#1{\fi}
\long\def\MYif@fifiAa#1\fi\fi#2#3{\fi#2}
\long\def\MYif@fifiAb#1\fi\fi#2#3{\fi#3}
\long\def\MYif@fifiBAa#1\fi\fi#2#3{\fi\fi#2}
\long\def\MYif@fifiBAb#1\fi\fi#2#3{\fi\fi#3}
\long\def\MYif@fifiBBa\fi\fi#1#2{\fi\fi#1}
\long\def\MYif@fifiBBb\fi\fi#1#2{\fi\fi#2}
% <<<
\newcommand*\MYif@groupify@TF[1]% >>>
  {%
    \expandafter\long\expandafter\edef\csname MYif#1GTF\endcsname##1%
      {%
        \unexpanded{\MYifGroupTF}{##1}%
          {\unexpanded\expandafter{\csname MYif#1GTF\endcsname}##1}%
          {\unexpanded\expandafter{\csname MYif#1TF\endcsname}{##1}}%
      }%
  }% <<<
\newcommand*\MYif@create@TandF[1]% >>>
  {%
    \expandafter\long\expandafter\edef\csname MYif#1T\endcsname##1%
      {%
        \unexpanded\expandafter{\csname MYif#1TF\endcsname}{##1}%
          {\noexpand\@firstofone}
          {\noexpand\@gobble}%
      }%
    \expandafter\long\expandafter\edef\csname MYif#1F\endcsname##1%
      {%
        \unexpanded\expandafter{\csname MYif#1TF\endcsname}{##1}%
          {\noexpand\@gobble}
          {\noexpand\@firstofone}%
      }%
  }% <<<
\newcommand*\MYif@create@TandF@twoargs[1]% >>>
  {%
    \expandafter\long\expandafter\edef\csname MYif#1T\endcsname##1##2%
      {%
        \unexpanded\expandafter{\csname MYif#1TF\endcsname}{##1}{##2}%
          {\noexpand\@firstofone}
          {\noexpand\@gobble}%
      }%
    \expandafter\long\expandafter\edef\csname MYif#1F\endcsname##1##2%
      {%
        \unexpanded\expandafter{\csname MYif#1TF\endcsname}{##1}{##2}%
          {\noexpand\@gobble}
          {\noexpand\@firstofone}%
      }%
  }% <<<
\newcommand*\MYif@create@N@TandF[1]% >>>
  {%
    \expandafter\long\expandafter\edef\csname MYif#1NTF\endcsname##1%
      {%
        \noexpand\expandafter
        \expandafter\noexpand\csname MYif#1TF\endcsname
        \noexpand\expandafter{##1}%
      }%
    \MYif@create@TandF{#1N}%
  }% <<<
\newcommand*\MYif@create@N@TandF@twoargs[1]% >>>
  {%
    \expandafter\long\expandafter\edef\csname MYif#1NNTF\endcsname##1##2%
      {%
        \noexpand\expandafter
        \expandafter\noexpand\csname MYif#1NNTF@a\endcsname
        \noexpand\expandafter{##2}{##1}%
      }%
    \expandafter\long\expandafter\edef\csname MYif#1NNTF@a\endcsname##1##2%
      {%
        \noexpand\expandafter
        \expandafter\noexpand\csname MYif#1TF\endcsname
        \noexpand\expandafter{##2}{##1}%
      }%
    \MYif@create@TandF@twoargs{#1NN}%
    \expandafter\long\expandafter\edef\csname MYif#1NnTF\endcsname##1##2%
      {%
        \noexpand\expandafter
        \expandafter\noexpand\csname MYif#1TF\endcsname
        \noexpand\expandafter{##1}{##2}%
      }%
    \MYif@create@TandF@twoargs{#1Nn}%
    \expandafter\long\expandafter\edef\csname MYif#1nNTF\endcsname##1##2%
      {%
        \noexpand\expandafter
        \expandafter\noexpand\csname MYif#1nNTF@a\endcsname
        \noexpand\expandafter{##2}{##1}%
      }%
    \expandafter\long\expandafter\edef\csname MYif#1nNTF@a\endcsname##1##2%
      {%
        \expandafter\noexpand\csname MYif#1TF\endcsname{##2}{##1}
      }%
    \MYif@create@TandF@twoargs{#1nN}%
  }% <<<
\newcommand*\MYif@create@TandF@N@TandF[1]% >>>
  {%
    \MYif@create@TandF{#1}%
    \MYif@create@N@TandF{#1}%
  }% <<<
\newcommand*\MYif@create@TandF@N@TandF@twoargs[1]% >>>
  {%
    \MYif@create@TandF@twoargs{#1}%
    \MYif@create@N@TandF@twoargs{#1}%
  }% <<<
\newcommand\MYif@notEmpty@noGroup@noSpace[2]% >>>
  {%
    \MYifEmptyTF{#1}
      {\@secondoftwo}
      {%
        \MYifContainsGroupTF{#1}
          {\@secondoftwo}
          {%
            \MYifContainsSpaceTF{#1}
              {\@secondoftwo}
              {#2}%
          }%
      }%
  }% <<<
% MYifEmpty >>>
\newcommand\MYifEmptyTF[1]% >>>
  {%
    \if\relax\detokenize{#1}\relax
      \MYif@fiAa
    \else
      \MYif@fiBb
    \fi
  }% <<<
\newcommand\MYifEmptyT[1]{% >>>
  \if\relax\detokenize{#1}\relax
    \MYif@fiAy
  \else
    \MYif@fiBn
  \fi}
% <<<
\newcommand\MYifEmptyF[1]{% >>>
  \if\relax\detokenize{#1}\relax
    \MYif@fiAn
  \else
    \MYif@fiBy
  \fi}
% <<<
\newcommand\MYifEmptyNTF[1]% >>>
  {\expandafter\MYifEmptyTF\expandafter{#1}}% <<<
\newcommand\MYifEmptyNT[1]% >>>
  {\expandafter\MYifEmptyT\expandafter{#1}}% <<<
\newcommand\MYifEmptyNF[1]% >>>
  {\expandafter\MYifEmptyF\expandafter{#1}}% <<<
\MYif@groupify@TF{Empty}
\MYif@create@TandF@N@TandF{EmptyG}
% <<<
% MYifContainsGroup >>>
\newcommand\MYifContainsGroupTF[1]% >>>
  {%
    \expandafter\MYifContainsGroup@a
      \MYifContainsGroup@eat#1{}%
    \MYifContainsGroup@endargument
  }% <<<
\long\def\MYifContainsGroup@eat#1#{}
\long\def\MYifContainsGroup@a#1\MYifContainsGroup@endargument% >>>
  {%
    \MYifEmptyTF{#1}
      {\@secondoftwo}
      {\@firstoftwo}%
  }% <<<
\MYif@groupify@TF{ContainsGroup}
\MYif@create@TandF@N@TandF{ContainsGroup}
\MYif@create@TandF@N@TandF{ContainsGroupG}
% <<<
% MYifContainsSpace >>>
\newcommand\MYifContainsSpaceTF[1]% >>>
  {%
    \expandafter\MYifContainsSpace@a
      \MYifContainsSpace@eat#1
    \MYifContainsSpace@endargument
  }% <<<
\long\def\MYifContainsSpace@a#1\MYifContainsSpace@endargument% >>>
  {%
    \MYifEmptyTF{#1}
      {\@secondoftwo}
      {\@firstoftwo}%
  }% <<<
\long\def\MYifContainsSpace@eat#1 {}
\MYif@groupify@TF{ContainsSpace}
\MYif@create@TandF@N@TandF{ContainsSpace}
\MYif@create@TandF@N@TandF{ContainsSpaceG}
% <<<
% MYifDigit >>>
\newcommand\MYifDigitTF[1]% >>>
  {%
    \MYifOneTokenNoGroupTF{#1}
      {\MYifDigit@a{#1}}
      {\@secondoftwo}%
  }% <<<
\newcommand\MYifDigit@a[1]% >>>
  {%
    \ifx0#1\MYif@fiAa
    \else\MYifDigit@b1#1%
    \else\MYifDigit@b2#1%
    \else\MYifDigit@b3#1%
    \else\MYifDigit@b4#1%
    \else\MYifDigit@b5#1%
    \else\MYifDigit@b6#1%
    \else\MYifDigit@b7#1%
    \else\MYifDigit@b8#1%
    \else\MYifDigit@b9#1%
    \else\MYif@fiBb
    \fi
  }% <<<
\newcommand\MYifDigit@b[2]% >>>
  {%
    \fi\ifx#1#2\MYif@fiAa
  }% <<<
\newcommand\MYifDigitGTF[1]% >>>
  {%
    \MYifGroupTF{#1}
      {\MYifDigitGTF#1}
      {%
        \MYifOneTokenTF{#1}
          {\MYifDigit@a{#1}}
          {\@secondoftwo}%
      }%
  }% <<<
\MYif@create@TandF@N@TandF{Digit}
\MYif@create@TandF@N@TandF{DigitG}
% <<<
% MYifNumber >>>
\newcommand\MYifNumberTF[1]% >>>
  {%
    \MYif@notEmpty@noGroup@noSpace{#1}{\MYifNumber@ifSign#1\endMYifargument}%
  }% <<<
\newcommand\MYifNumber@ifSign[1]% >>>
  {%
    \ifx+#1%
      \MYif@fifiAa
    \else
      \ifx-#1%
        \MYif@fifiBAa
      \else
        \MYif@fifiBBb
      \fi
    \fi
    {\MYifNumber@ifDigit@noend}
    {\MYifNumber@ifDigit#1}
  }% <<<
\newcommand\MYifNumber@ifDigit[1]% >>>
  {%
    \MYif@endMYifargument{#1}
      {\@firstoftwo}
      {%
        \MYifDigit@a{#1}
          {\MYifNumber@ifDigit}
          {\MYifNumber@false}%
      }%
  }% <<<
\newcommand\MYifNumber@ifDigit@noend[1]% >>>
  {%
    \MYif@endMYifargument{#1}
      {\@secondoftwo}
      {%
        \MYifDigit@a{#1}
          {\MYifNumber@ifDigit}
          {\MYifNumber@false}%
      }%
  }% <<<
\long\def\MYifNumber@false#1\endMYifargument% >>>
  {%
    \@secondoftwo
  }% <<<
\MYif@groupify@TF{Number}
\MYif@create@TandF@N@TandF{Number}
\MYif@create@TandF@N@TandF{NumberG}
% <<<
% MYifFloat >>>
\newcommand\MYifFloatTF[1]% >>>
  {%
    \MYif@notEmpty@noGroup@noSpace{#1}{\MYifFloat@a{#1}}
  }% <<<
%\newcommand\MYifFloat@a \newcommand\MYifFloat@ifDot >>>
\begingroup
\catcode`\?=4
\def\MYif@zz
  {%
    \endgroup
    \newcommand\MYifFloat@a[1]% >>>
      {%
        \MYifFloat@ifDot{##1}
          {\MYifFloat@withDot##1\MYifFloat@endargument}
          {\MYifNumber@ifSign##1\endMYifargument}%
      }% <<<
    \newcommand\MYifFloat@ifDot[1]% >>>
      {%
        \MYifFloat@ifDot@a##1.?\MYifFloat@endargument
      }% <<<
    \long\def\MYifFloat@ifDot@a##1.##2\MYifFloat@endargument% >>>
      {%
        \ifx?##2%
          \MYif@fiAb
        \else
          \MYif@fiBa
        \fi
      }% <<<
  }
\MYif@zz
% <<<
\long\def\MYifFloat@withDot#1.#2\MYifFloat@endargument% >>>
  {%
    \MYifEmptyTF{#1}
      {\MYifNumber@ifDigit@noend#2\endMYifargument}
      {%
        \MYifNumber@ifSign#1\endMYifargument
          {\MYifNumber@ifDigit#2\endMYifargument}
          {\@secondoftwo}%
      }%
  }% <<<
\MYif@groupify@TF{Float}
\MYif@create@TandF@N@TandF{Float}
\MYif@create@TandF@N@TandF{FloatG}
% <<<
% MYifContainsE >>>
\newcommand\MYifContainseTF[1]% >>>
  {%
    \MYifContainsE@e#1e\MYifContainsE@end
      {\@secondoftwo}
      {\@firstoftwo}%
  }% <<<
\long\def\MYifContainsE@e#1e#2\MYifContainsE@end% >>>
  {%
    \MYifEmptyTF{#2}%
  }% <<<
\newcommand\MYifContainsETF[1]% >>>
  {%
    \MYifContainsE@E#1E\MYifContainsE@end
      {\@secondoftwo}
      {\@firstoftwo}%
  }% <<<
\long\def\MYifContainsE@E#1E#2\MYifContainsE@end% >>>
  {%
    \MYifEmptyTF{#2}%
  }% <<<
% <<<
% MYifScientific >>>
\newcommand\MYifScientificTF[1]% >>>
  {%
    \MYifContainsETF{#1}
      {\MYifScientific@withE#1\endMYifScientific}
      {%
        \MYifContainseTF{#1}
          {\MYifScientific@withe#1\endMYifScientific}
          {\MYifFloatTF{#1}}%
      }%
  }% <<<
\long\def\MYifScientific@withE#1E#2\endMYifScientific% >>>
  {%
    \MYifFloatTF{#1}
      {\MYifNumberTF{#2}}
      {\@secondoftwo}%
  }% <<<
\long\def\MYifScientific@withe#1e#2\endMYifScientific% >>>
  {%
    \MYifFloatTF{#1}
      {\MYifNumberTF{#2}}
      {\@secondoftwo}%
  }% <<<
\MYif@groupify@TF{Scientific}
\MYif@create@TandF@N@TandF{Scientific}
\MYif@create@TandF@N@TandF{ScientificG}
% <<<

\makeatother

\usepackage{pgf}

\begin{document}
\def\testNum{3e+64}

\MYifScientificNTF{\testNum}
  {%
    \pgfmathprintnumber[sci]{\testNum} is a number
  }
  {%
    \pgfmathprintnumber[sci]{\testNum} is not a number
  }
\end{document}

相关内容