\fp_eval 的输入清理

\fp_eval 的输入清理

是否有命令询问参数是否\fp_eval是解析错误?例如:

\fp_if_valid:nTF { 1+2.3*2 } { yes } { no } % yes
\fp_if_valid:nTF { 1+2.3*  } { yes } { no } % no

我希望能够清理用户输入,如果他们的输入无效,则抛出我自己的错误。无论如何,我只是好奇是否有内置命令可以执行此操作,或者 latex3 团队是否打算添加此功能。我编写了以下代码,它似乎有效(感谢 Rob Hall 修复了一些错误):

\documentclass{article}
\usepackage{xfp}

\ExplSyntaxOn
% Add missing variant based on definition of \exp_last_unbraced:Nf in l3expan.dtx    
\cs_set:Npn \exp_last_unbraced:NNf #1#2#3
    { \exp_after:wN #1 \exp_after:wN #2 \exp:w \exp_end_continue_f:w #3 }

\tl_new:N \l_my_fp_if_valid_tl

% \return_marker: for maintaining true/false state outside \fp_eval program flow
\scan_new:N \my_fp_if_valid_return_marker:
% Protected wrappers for \prg_return_true: and \prg_return_false:
\cs_new_protected:Nn \my_fp_if_valid_return_true:  { \prg_return_true:  }
\cs_new_protected:Nn \my_fp_if_valid_return_false: { \prg_return_false: }

% Replace "\return_marker: \return_<true or false>:" 
% with "\return_marker: \return_false:"
\cs_new:Npn \my_fp_if_valid_set_return_false:wN #1 \my_fp_if_valid_return_marker: #2
    { #1 \my_fp_if_valid_return_marker: \my_fp_if_valid_return_false: }

\prg_new_protected_conditional:Nnn \my_fp_if_valid:n {T, F, TF} {
    \group_begin:
        % make error command throw away error message and call \set_return_false:wN
        \cs_set:Nn \__msg_expandable_error:n { \my_fp_if_valid_set_return_false:wN }
        % Sets \l_if_valid_tl to 
        % "<numerical result> \return_marker: \return_<true or false>:"
        \tl_set:Nx \l_my_fp_if_valid_tl { 
            \fp_eval:n { #1 } 
            \my_fp_if_valid_return_marker: \my_fp_if_valid_return_true:
        }
    % Put <numerical result> into \result: and evaluate \return_<true or false>:
    \exp_last_unbraced:NNf \group_end:
        \my_fp_if_valid_helper:w \tl_use:N \l_my_fp_if_valid_tl
}

% Put <numerical result> into \result:
\cs_new:Npn \my_fp_if_valid_helper:w #1 \my_fp_if_valid_return_marker: {
    \cs_set:Nn \my_fp_if_valid_result: { #1 }
} 

\cs_new_eq:NN \fpifvalid \my_fp_if_valid:nTF

\ExplSyntaxOff

\usepackage{xcolor}
\def\testfpifvalid#1{\fpifvalid{#1}{\color{blue}}{\color{red}}\texttt{#1}\par}
\begin{document}

\testfpifvalid{1+1}             % valid
\testfpifvalid{1+}              % invalid
\testfpifvalid{1+2.3*2}         % valid
\testfpifvalid{1+2.3 2}         % valid
\testfpifvalid{1+2.3.*2}        % invalid
\testfpifvalid{1++2}            % valid
\testfpifvalid{1+*2}            % invalid
\testfpifvalid{1*+2}            % valid
\testfpifvalid{1/0}             % invalid
\testfpifvalid{1)2}             % invalid
\testfpifvalid{1(2}             % invalid
\testfpifvalid{1(2)}            % valid
\testfpifvalid{1+1(2/6)+sin(7)} % valid
\testfpifvalid{floor(6,-1)}     % valid
\testfpifvalid{floor(6,7,7)}    % invalid

\end{document} 

答案1

我在 2020 年遇到了这个问题,有同样的需求。我(和 OP 一样)不知道目前 LaTeX3 接口中是否还有其他现成的解决方案。如果您想使用此方法,需要解决以下问题:

  1. OP 示例代码中的一些小拼写错误需要解决
  2. \__scan_new:N已搬迁

对于那些希望使用 OP 代码进行复制粘贴解决方案的人来说,请采取以下措施

% depends on xfp, pgfmath
\usepackage{xfp}
\usepackage{pgfmath}

\ExplSyntaxOn
% Add missing variant based on definition of \exp_last_unbraced:Nf in l3expan.dtx    
\cs_set:Npn \exp_last_unbraced:NNf #1#2#3
    { \exp_after:wN #1 \exp_after:wN #2 \exp:w \exp_end_continue_f:w #3 }

\tl_new:N \l_my_fp_if_valid_tl

% \return_marker: for maintaining true/false state outside \fp_eval program flow
\scan_new:N \my_fp_if_valid_return_marker:
% Protected wrappers for \prg_return_true: and \prg_return_false:
\cs_new_protected:Nn \my_fp_if_valid_return_true:  { \prg_return_true:  }
\cs_new_protected:Nn \my_fp_if_valid_return_false: { \prg_return_false: }

% Replace "\return_marker: \return_<true or false>:" 
% with "\return_marker: \return_false:"
\cs_new:Npn \my_fp_if_valid_set_return_false:wN #1 \my_fp_if_valid_return_marker: #2
    { #1 \my_fp_if_valid_return_marker: \my_fp_if_valid_return_false: }

\prg_new_protected_conditional:Nnn \my_fp_if_valid:n {T, F, TF} {
    \group_begin:
        % make error command throw away error message and call \set_return_false:wN
        \cs_set:Nn \__msg_expandable_error:n { \my_fp_if_valid_set_return_false:wN }
        % Sets \l_if_valid_tl to 
        % "<numerical result> \return_marker: \return_<true or false>:"
        \tl_set:Nx \l_my_fp_if_valid_tl { 
            \fp_eval:n { #1 } 
            \my_fp_if_valid_return_marker: \my_fp_if_valid_return_true:
        }
    % Put <numerical result> into \result: and evaluate \return_<true or false>:
    \exp_last_unbraced:NNf \group_end:
        \my_fp_if_valid_helper:w \tl_use:N \l_my_fp_if_valid_tl
}

% Put <numerical result> into \result:
\cs_new:Npn \my_fp_if_valid_helper:w #1 \my_fp_if_valid_return_marker: {
    \cs_set:Nn \my_fp_if_valid_result: { #1 }
} 

\cs_new_eq:NN \fpifvalid \my_fp_if_valid:nTF

\ExplSyntaxOff

OP 的原始演示现在将继续进行

% demo depends on xcolor
\usepackage{xcolor}
\begin{document}
\def\testfpifvalid#1{\fpifvalid{#1}{\color{blue}}{\color{red}}\texttt{#1}\par}
\testfpifvalid{1+1}             % valid
\testfpifvalid{1+}              % invalid
\testfpifvalid{1+2.3*2}         % valid
\testfpifvalid{1+2.3 2}         % valid
\testfpifvalid{1+2.3.*2}        % invalid
\testfpifvalid{1++2}            % valid
\testfpifvalid{1+*2}            % invalid
\testfpifvalid{1*+2}            % valid
\testfpifvalid{1/0}             % invalid
\testfpifvalid{1)2}             % invalid
\testfpifvalid{1(2}             % invalid
\testfpifvalid{1(2)}            % valid
\testfpifvalid{1+1(2/6)+sin(7)} % valid
\testfpifvalid{floor(6,-1)}     % valid
\testfpifvalid{floor(6,7,7)}    % invalid

相关内容