目標是讓使用者輸入(為了論證)一個變數中的線性函數,例如2*x+3
變數(這並不重要)和變數的值。然後我想計算該函數的值。以下內容有效,但我現在認為它的工作更多是出於偶然而不是其他任何事情。
我最初的嘗試
\findvalueB
失敗了,而且似乎不喜歡下劃線,所以我嘗試了\findvalueA
其中有效的方法。為什麼其中一個有效而另一個無效?當決定切換變數名稱進行測試時,我遇到了明顯的問題(例如使用
y
中斷)\mytoks
。 所以我嘗試對變數名稱進行硬編碼,再次失敗。
據推測,我沒有得到的東西有一個共同點,這可能是對我想糾正的事情的根本誤解。我對解釋比代碼解決方案更感興趣,儘管兩者都很好。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\newtoks\mytoks
\NewDocumentCommand {\findvalueA} { m m m }
{
\group_begin:
\char_set_catcode_active:N #1
\tl_rescan:nn{}{\def#1{#2}}
\tl_rescan:nn{}{\mytoks={#3}}
\fp_set:Nn \l_tmpa_fp {\the\mytoks}
\fp_use:N \l_tmpa_fp
\group_end:
}
\NewDocumentCommand {\findvalueB} { m m m }
{
\group_begin:
\char_set_catcode_active:N #1
\tl_rescan:nn{}{\def#1{#2}}
% underscores=bad
\tl_rescan:nn{}{\tl_set:Nn \l_tmpa_tl {#3}}
% or
% \tl_rescan:nn{}{\fp_eval:n {#3}}
\fp_use:N \l_tmpa_fp
\group_end:
}
\NewDocumentCommand {\findvalueC} { m m }
{
\group_begin:
\char_set_catcode_active:N x
\tl_rescan:nn {} {\defx{#1}}
\tl_rescan:nn {} {\mytoks={#2}}
\fp_set:Nn \l_tmpa_fp {\the\mytoks}
\fp_use:N \l_tmpa_fp
\group_end:
}
\ExplSyntaxOff
\begin{document}
% works
\findvalueA{x}{5}{2*x+3}
% fails
%\findvalueB{x}{5}{2*x+3}
% fails
%\findvalueC{5}{x+2}
The method of findvalueC works down here but not above: if $x=5$, then $x+2=$
\ExplSyntaxOn
\group_begin:
\char_set_catcode_active:N x
\defx{5}
\fp_eval:n {x+2}
\group_end:
\ExplSyntaxOff
\end{document}
答案1
方法 B 的失敗很容易解釋。重新掃描材料會讀取目前適用的類別代碼。當你使用 \findvalueB
,您在文件中,因此有類別“數學下標”,而不是“字母”(稍後_
您還會發現這是錯誤的)。:
人們常常對此感到驚訝,因為他們想像重新掃描將使用定義命令時設定的程式碼。這是使重新掃描變得非常棘手的一件事。
方法C的失敗更難修復。這裡發生的情況是,TeX\defx
在執行重新掃描之後「有用地」插入一個空格,就像在更改標記化時在任何其他控制序列之後(例如 in\write
或\detokenize
)一樣。這發生在重新掃描“之前”,其中\defx
將是單一令牌。結果是,在方法 C 中x
被定義為後面跟著一個必要的空格:沒有空格,所以我們得到錯誤。在方法 A 中不會發生這種情況,因為此處的空格是在重新掃描之前\def
和之前插入的#1
(它們是重新掃描之前的單獨標記)。因此這個方法會起作用。
這兩個問題都說明了為什麼重新掃描不受許多 TeX 程式設計師的青睞:我傾向於避免它。我們在 LaTeX3 中提供了合理的包裝器,但是您的問題表明要正確使用它仍然很棘手。您真正想要的是將所有變數字母替換為值。因此,我根本不會重新掃描,而是會使用
\NewDocumentCommand { \findvalueD } { m m m }
{
\tl_set:Nn \l_tmpa_tl {#3}
\tl_replace_all:Nnn \l_tmpa_tl {#1} {#2}
\fp_eval:n { \l_tmpa_tl }
}
不存在任何這些問題。 (我假設您沒有sin
在表達式和字母中n
作為可能的變數:可以處理這種情況,但需要更多思考!)