使用该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}
由于我是这个列表的新成员,我还不能发表评论。以下是新的结果——伟大的!!!