通过 l3regex 将 xfp 符号转换为 LaTeX 符号

通过 l3regex 将 xfp 符号转换为 LaTeX 符号

使用该xfp包来计算数学术语效果非常好,而且我正在尝试自动化一些操作以使\fp_eval:n输入也能用 LaTeX 符号正确呈现。

因此,我尝试使用l3regex命令来匹配必要的表达式。

现在使用以下命令,\regex_replace_all:nnN { (\() (.*) (\)/\() (.*) (\)) } { \c{frac} \cB\{ \2\cE\} \cB\{ \4\cE\} } \l_juergen_func_tl第一个例子可以正常工作,但第二个例子却失败了。

代码:

\documentclass{article}
\usepackage{xfp}

\begin{document}

\ExplSyntaxOn

\NewDocumentCommand{\showfuncandvalue}{ m m }
{% #1 = value, #2 = function
  \tl_set:Nn                                        \l_juergen_func_tl  { #2 }
    \regex_replace_all:nnN { \* } { \c{cdot} }      \l_juergen_func_tl
    \regex_replace_all:nnN { (\() (.*) (\)/\() (.*) (\)) } { \c{frac} \cB\{ \2\cE\} \cB\{ \4\cE\} }  \l_juergen_func_tl

    f(x) = \l_juergen_func_tl
    ;\quad
    f(#1) = \juergen_showfunc_value:nn { #1 } { #2 }
}

\cs_new_protected:Nn \juergen_showfunc_value:nn
{
  \tl_set:Nn                               \l_juergen_func_tl { #2 }
  \regex_replace_all:nnN { x } { (x) }     \l_juergen_func_tl
  \regex_replace_all:nnN { x } { \cP\#1 }  \l_juergen_func_tl
  \cs_set:NV \__juergen_showfunc_f:n       \l_juergen_func_tl
  \fp_eval:n
   {
    round ( \__juergen_showfunc_f:n { ( \fp_eval:n { ( #1 ) } ) } , 4 )
   }
}
\cs_generate_variant:Nn \cs_set:Nn { NV }

\ExplSyntaxOff

$$ \showfuncandvalue{2}{x-(4*x+3x^2)/(3-(2*x+x^2)) + 16} $$
$$ \showfuncandvalue{2}{(x+1)-(4*x+3x^2)/(3-(2*x+x^2)) - (16-x)} $$

The correct notation for the second example should be:
$$(x+1)-\frac{4\cdot x+3x^2}{3-(2\cdot x+x^2)}-(16-x)$$
\end{document}

在此处输入图片描述

现在我的问题是如何使 regEx 模式更加智能,以使第二个示例正常运行。笔记:分数前面可能有更多对括号,当然分数后面也可能有更多对括号,而我在示例中没有设置。

我的正则表达式模式找不到正确匹配的括号,这是很明显的。

任何能够构建可以将语法转换为 LaTeX 语法的 regEx 模式的帮助xfp都将不胜感激。

答案1

我认为反过来会更容易,从 LaTeX 语法开始:在正则表达式中平衡括号或大括号并不容易,但 TeX 可以毫无问题地平衡大括号,并且\fpeval可以在其参数中处理宏和大括号:

\documentclass{scrbook}
\usepackage{xfp}
\ExplSyntaxOn
\newcommand\fpdiv[2]{(#1)/(#2)}
\NewDocumentCommand{\showfuncandvalue}{ m m }
{% #1 = value, #2 = function
  \tl_set:Nn                                        \l_juergen_func_tl  { #2 }
    \regex_replace_all:nnN { ([0-9])x } { \1\*#1 }  \l_juergen_func_tl
    %\tl_show:N\l_juergen_func_tl
    \regex_replace_all:nnN { x } { #1 }             \l_juergen_func_tl
    %\tl_show:N\l_juergen_func_tl
    \regex_replace_all:nnN { \c{cdot} } { \* }      \l_juergen_func_tl
    %\tl_show:N\l_juergen_func_tl
    \regex_replace_all:nnN { \c{frac} } { \c{fpdiv} }\l_juergen_func_tl
    %\tl_show:N\l_juergen_func_tl

  f(x) = #2
  ;\quad
  f(#1) = \fp_eval:n{\l_juergen_func_tl}
}

\ExplSyntaxOff
\begin{document}

\[\showfuncandvalue{2}{x-\frac{4x+3x^2}{3-(2x+x^2)} + 16}\]

\[\showfuncandvalue{2}{(x+1)-\frac{4\cdot x+3x^2}{3-(2\cdot x+x^2)}-(16-x)}\]

\[\showfuncandvalue{2}{(x+1)-\frac{4\cdot x+3x^2}{3-(2\cdot x+x^{(1+1)})}-(16-x)}\]


\end{document}

在此处输入图片描述

答案2

这里我选择将每个左括号改为\juergenparen(,然后让xparse的分隔符匹配代码完成其工作(使用可扩展命令允许进一步的代码预览下一个标记)。一旦每个括号组都被 替换\__juergen_paren:n { ... },该函数就会查找/并跟随它,如果相关则将\__juergen_paren:n { ... }其包装进去。\frac

\documentclass{article}
\usepackage{xfp}

\begin{document}

\ExplSyntaxOn

\tl_new:N \l__juergen_func_tl
\fp_new:N \l__juergen_func_fp
\NewDocumentCommand{\showfuncandvalue}{ m m }
  { % #1 = value, #2 = function
    \juergen_showfunc_math:n {#2} ; \quad
    \juergen_showfunc_value:nn {#1} {#2}
  }
\cs_new_protected:Nn \juergen_showfunc_math:n
  {
    \juergen_showfunc_math_get:nN {#1} \l__juergen_func_tl
    f(x) = \l__juergen_func_tl
  }
\cs_new_protected:Nn \juergen_showfunc_math_get:nN
  {
    \tl_set:Nn #2 {#1}
    \tl_replace_all:Nnn #2 { * } { \exp_not:N \cdot } % Later we do x-expansion.
    % Wrap single-term numerator/denominator (such as "2*x^2") in parentheses.
    \regex_replace_all:nnN { ( [\w\^\*]+ ) \s* \/ } { \( \1 \) \/ } #2
    \regex_replace_all:nnN { \/ \s* ( [\w\^]+ ) } { \/ \( \1 \) } #2
    % Insert and expand "\juergenparen", which balances parentheses.
    \tl_replace_all:Nnn #2 { ( } { \juergenparen ( }
    \tl_set:Nx #2 {#2}
  }
\NewExpandableDocumentCommand {\juergenparen} {r()} { \__juergen_paren:n {#1} }
\cs_new_protected:Nn \__juergen_paren:n
  {
    \peek_charcode_remove_ignore_spaces:NTF /
      { \__juergen_paren_div:n {#1} }
      { (#1) }
  }
\cs_new_protected:Nn \__juergen_paren_div:n
  {
    \peek_meaning_remove_ignore_spaces:NTF \__juergen_paren:n
      { \__juergen_paren_div:nn {#1} }
      { (#1) / \msg_error:nnn { juergen } { no-denominator } {#1} }
  }
\cs_new_protected:Nn \__juergen_paren_div:nn { \frac{#1}{#2} }
\msg_new:nnn { juergen } { no-denominator }
  { No~denominator~after~"(#1)/". }
\cs_new_protected:Nn \juergen_showfunc_value:nn
  {
    \fp_set:Nn \l__juergen_func_fp {#1}
    \tl_set:Nn \l__juergen_func_tl {#2}
    \tl_replace_all:Nnn \l__juergen_func_tl { x } { \l__juergen_func_fp }
    f ( \fp_use:N \l__juergen_func_fp )
    = \fp_eval:n { round ( \l__juergen_func_tl , 4 ) }
  }

\ExplSyntaxOff

\[ \showfuncandvalue{2}{x-(4*x+3x^2)/(3-(2*x+x^2)) + 16} \]
\[ \showfuncandvalue{2}{(x+1)-(4*x+3x^2)/(3-(2*x+x^2)) - (16-x)} \]

The correct notation for the second example should be:
\[(x+1)-\frac{4\cdot x+3x^2}{3-(2\cdot x+x^2)}-(16-x)\]
\end{document}

对于“值”部分,与其将值括在括号中并重新计算几次,不如像我在这里所做的那样将其保存在浮点变量中,然后用它替换所有x内容。请注意,x如果使用标记列表变量,那么对于负数(例如 -1),这将严重失败:x^2将变成\l_my_tl ^2,这将扩展为-1^2,解析为-(1^2)。相比之下,浮点变量有额外的信息,告诉l3fp(底层xfp)将它们视为单个对象,从而得到(-1)^2

答案3

谢谢乌尔丽克·菲舍尔的回答是“反向尝试”(这使得与 RegEx 相关的事变得容易得多),我稍微修改了她的代码,以便#1也可以使用 LaTeX 语法输入,现在还允许使用逗号作为小数分隔符。

这件事情让我感到很快乐:

\documentclass{article}
\usepackage{siunitx,xfp}
\sisetup{output-decimal-marker = {,}}
\ExplSyntaxOn
\newcommand\fpdiv[2]{(#1)/(#2)}
\newcommand\fpsqrt[1]{sqrt(#1)}
\NewDocumentCommand{\showfuncandvalue}{ m m }
{% #1 = value, #2 = function
  \tl_set:Nn                                           \l_juergen_value_tl { #1 }
    \regex_replace_all:nnN { \c{ln} } { ln }           \l_juergen_value_tl
    \regex_replace_all:nnN { \c{frac} } { \c{fpdiv} }  \l_juergen_value_tl
    \regex_replace_all:nnN { \c{sqrt} } { \c{fpsqrt} } \l_juergen_value_tl
    \regex_replace_all:nnN { \c{cdot} } { \* }         \l_juergen_value_tl
    \regex_replace_all:nnN { , } { \. }                \l_juergen_value_tl
%---------------------------------------------------------------------------------
  \tl_set:Nn                                           \l_juergen_func_tl  { #2 }
    \regex_replace_all:nnN { ([0-9])x } { \1\*(\c{l_juergen_value_tl}) }   \l_juergen_func_tl
    \regex_replace_all:nnN { x }        { (\c{l_juergen_value_tl}) }       \l_juergen_func_tl
    \regex_replace_all:nnN { \c{cdot} } { \* }         \l_juergen_func_tl
    \regex_replace_all:nnN { \c{ln} } { ln }           \l_juergen_func_tl
    \regex_replace_all:nnN { \c{frac} } { \c{fpdiv} }  \l_juergen_func_tl
    \regex_replace_all:nnN { \c{sqrt} } { \c{fpsqrt} } \l_juergen_func_tl
    \regex_replace_all:nnN { , } { \. }                \l_juergen_func_tl
  f(x) = #2
  ;\quad
  f(#1) = \num { \fp_eval:n { \l_juergen_func_tl} }
}
\ExplSyntaxOff

\begin{document}
\[\showfuncandvalue{-2\cdot\sqrt{2}}{x-\frac{4x+3x^2}{3-(2x+x^2)} + 16}\]

\[\showfuncandvalue{\ln(2)}{(x+1)-\frac{4\cdot x+3x^2}{3-(2\cdot x+x^2)}-(16-x)}\]

\[\showfuncandvalue{2^{\ln(2)}}{-\frac{\frac{\sqrt{2,34}\cdot 3}{\sqrt{3}-1}}{\frac{2\cdot x}{3}}\cdot (x+1)-\frac{4\cdot x+3\cdot x^2}{3-(2\cdot x+x^{(1+1)})}-(16-x)}\]
\end{document}

由于我是这个列表的新成员,我还不能发表评论。以下是新的结果——伟大的!!!

在此处输入图片描述

相关内容