后续行动这个答案\getRow
,如何稳健地使用存储在多项式的系数中的值来打印?
另外,我需要有一个在多项式中使用的符号的参数。(它就v
在这个 MWE 中)
请注意,单元格中的零用作多项式项的系数,而空白单元格不用于多项式构造(即Third
此处的情况)
\begin{filecontents*}[overwrite]{mycoeffs.csv}
First , 4 , 0 , 2 , 5
Second , 0 , 0 , 7 , 8
Third , 5 , 0 , 6 ,
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% Step 1: reading the file
\ior_new:N \l__diaa_csv_ior
\bool_new:N \l__diaa_csv_str_bool
\seq_new:N \l__diaa_csv_tmp_seq
% str mode (bool/star), key column, label, value columns, file
\NewDocumentCommand \ReadCSV { s O{1} m O{} m }
{
\IfBooleanTF {#1}
{ \bool_set_true:N \l__diaa_csv_str_bool }
{ \bool_set_false:N \l__diaa_csv_str_bool }
\diaa_csv_read:nnnn {#3} {#2} {#4} {#5}
}
% label, key column, value columns, file
\cs_new_protected:Npn \diaa_csv_read:nnnn #1 #2 #3 #4
{
\tl_if_blank:nTF {#3} % Detect number of columns and use 2 to last
{
\ior_open:NnTF \l__diaa_csv_ior {#4}
{
\bool_if:NTF \l__diaa_csv_str_bool
{ \ior_str_get:NN }
{ \ior_get:NN }
\l__diaa_csv_ior \l_tmpa_tl
\ior_close:N \l__diaa_csv_ior
\seq_set_split:NnV \l_tmpa_seq { , } \l_tmpa_tl
\seq_clear:N \l__diaa_csv_tmp_seq
\int_step_inline:nnn { 2 } { \seq_count:N \l_tmpa_seq }
{ \seq_put_right:Nn \l__diaa_csv_tmp_seq {##1} }
}
{ \msg_error:nnn { diaa } { file-not-found } {#4} }
}
{ \seq_set_split:Nnn \l__diaa_csv_tmp_seq { , } {#3} } % explicit columns
\ior_open:NnTF \l__diaa_csv_ior {#4}
{
\prop_new:c { g__diaa_csv_#1_prop }
\__diaa_csv_read:nn {#1} {#2}
\ior_close:N \l__diaa_csv_ior
}
{ \msg_error:nnn { diaa } { file-not-found } {#4} }
}
\msg_new:nnn { diaa } { file-not-found }
{ File~`#1'~not~found. }
\cs_generate_variant:Nn \prop_put:Nnn { cxV }
% label, key column
\cs_new_protected:Npn \__diaa_csv_read:nn #1 #2
{
\bool_if:NTF \l__diaa_csv_str_bool
{ \ior_str_map_inline:Nn }
{ \ior_map_inline:Nn }
\l__diaa_csv_ior
{
\seq_set_split:Nnn \l_tmpa_seq { , } {##1} % split one CSV row
\tl_clear:N \l_tmpa_tl
\seq_map_inline:Nn \l__diaa_csv_tmp_seq
{
\tl_put_right:Nx \l_tmpa_tl { { \seq_item:Nn \l_tmpa_seq {####1} } }
}
\prop_put:cxV { g__diaa_csv_#1_prop }
{ \seq_item:Nn \l_tmpa_seq {#2} }
\l_tmpa_tl
}
}
% Step 2: getting the values
% star → global assignment, macro or tl var, value column, key, label
\NewDocumentCommand \getValue { s m O{1} m m }
{
\IfBooleanTF {#1} { \tl_gset:Nx } { \tl_set:Nx }
#2 { \diaa_csv_item:nnn {#4} {#3} {#5} }
}
% key, value column, label
\NewExpandableDocumentCommand \CSVItem { m O{1} m }
{ \diaa_csv_item:nnn {#1} {#2} {#3} }
\cs_generate_variant:Nn \tl_item:nn { f }
% key, value column, label
\cs_new:Npn \diaa_csv_item:nnn #1 #2 #3
{
\tl_item:fn { \prop_item:cn { g__diaa_csv_#3_prop } {#1} } {#2}
}
% star → global assignment, macro, key, label
\NewDocumentCommand \getRow { s m m m }
{
\prop_get:cnN { g__diaa_csv_#4_prop } {#3} \l_tmpa_tl
\IfBooleanTF {#1} { \cs_gset_nopar:Npx } { \cs_set_nopar:Npx } #2 [ ##1 ]
{
\exp_not:N \str_if_eq:nnTF {##1} { non-empty }
{
\exp_not:N \__diaa_nb_nonempty_items_in_row:nw { 0 }
\exp_not:V \l_tmpa_tl
\exp_not:n { \q_recursion_tail \q_recursion_stop }
}
{ \exp_not:N \tl_item:nn { \exp_not:V \l_tmpa_tl } {##1} }
}
}
\cs_new:Npn \__diaa_nb_nonempty_items_in_row:nw #1#2
{
\quark_if_recursion_tail_stop_do:nn {#2} { \int_eval:n {#1} }
\tl_if_empty:nTF {#2}
{ \__diaa_nb_nonempty_items_in_row:nw {#1} }
{ \__diaa_nb_nonempty_items_in_row:nw { #1 + 1 } }
}
\ExplSyntaxOff
\begin{document}
\ReadCSV{mydata}{mycoeffs.csv}
\getRow\First{First}{mydata}
I need to use \verb|\First| to print $4 \times v^3 + 2 \times v + 5$
\getRow\Second{Second}{mydata}
I need to use \verb|\Second| to print $7 \times v + 8$
\getRow\Third{Third}{mydata}
I need to use \verb|\Third| to print $5 \times v^2 + 6$
\end{document}
答案1
我提出以下建议。为了便于理解,我删除了本例中未使用的宏,但下面的代码与它所基于的代码兼容(即,您可以重新添加、以及它们所依赖的任何低级宏的定义\getValue
;\CSVItem
这\getRow
不会引起任何冲突)。
\begin{filecontents*}{test.csv}
First , 4 , 0 , 2 , 5
Second , 0 , 0 , 7 , 8
Third , 5 , 0 , 6 ,
Fourth , -5 , 0 , -6 ,
\end{filecontents*}
\documentclass{article}
% Uncomment if the LaTeX format is older than 2020-10-01:
% \usepackage{xparse}
\ExplSyntaxOn
% Reading the file (based on <https://tex.stackexchange.com/a/575055/73317>)
\ior_new:N \l__diaa_csv_ior
\bool_new:N \l__diaa_csv_str_bool
\seq_new:N \l__diaa_csv_tmp_seq
% str mode (bool/star), key column, label, value columns, file
\NewDocumentCommand \ReadCSV { s O{1} m O{} m }
{
\IfBooleanTF {#1}
{ \bool_set_true:N \l__diaa_csv_str_bool }
{ \bool_set_false:N \l__diaa_csv_str_bool }
\diaa_csv_read:nnnn {#3} {#2} {#4} {#5}
}
% label, key column, value columns, file
\cs_new_protected:Npn \diaa_csv_read:nnnn #1 #2 #3 #4
{
\tl_if_blank:nTF {#3} % Detect number of columns and use 2 to last
{
\ior_open:NnTF \l__diaa_csv_ior {#4}
{
\bool_if:NTF \l__diaa_csv_str_bool
{ \ior_str_get:NN }
{ \ior_get:NN }
\l__diaa_csv_ior \l_tmpa_tl
\ior_close:N \l__diaa_csv_ior
\seq_set_split:NnV \l_tmpa_seq { , } \l_tmpa_tl
\seq_clear:N \l__diaa_csv_tmp_seq
\int_step_inline:nnn { 2 } { \seq_count:N \l_tmpa_seq }
{ \seq_put_right:Nn \l__diaa_csv_tmp_seq {##1} }
}
{ \msg_error:nnn { diaa } { file-not-found } {#4} }
}
{ \seq_set_split:Nnn \l__diaa_csv_tmp_seq { , } {#3} } % explicit columns
\ior_open:NnTF \l__diaa_csv_ior {#4}
{
\prop_new:c { g__diaa_csv_#1_prop }
\__diaa_csv_read:nn {#1} {#2}
\ior_close:N \l__diaa_csv_ior
}
{ \msg_error:nnn { diaa } { file-not-found } {#4} }
}
\msg_new:nnn { diaa } { file-not-found }
{ File~`#1'~not~found. }
\cs_generate_variant:Nn \prop_put:Nnn { cxV }
% label, key column
\cs_new_protected:Npn \__diaa_csv_read:nn #1 #2
{
\bool_if:NTF \l__diaa_csv_str_bool
{ \ior_str_map_inline:Nn }
{ \ior_map_inline:Nn }
\l__diaa_csv_ior
{
\seq_set_split:Nnn \l_tmpa_seq { , } {##1} % split one CSV row
\tl_clear:N \l_tmpa_tl
\seq_map_inline:Nn \l__diaa_csv_tmp_seq
{
\tl_put_right:Nx \l_tmpa_tl { { \seq_item:Nn \l_tmpa_seq {####1} } }
}
\prop_put:cxV { g__diaa_csv_#1_prop }
{ \seq_item:Nn \l_tmpa_seq {#2} }
\l_tmpa_tl
}
}
\keys_define:nn { diaa / getPolyFromRow }
{
global-assignment .bool_set:N = \l__diaa_gpfr_global_assignment_bool,
global-assignment .default:n = true,
global-assignment .initial:n = false,
variable .tl_set:N = \l__diaa_gpfr_variable_name_tl,
variable .value_required:n = true,
variable .initial:n = X,
typographical-variant .str_set:N = \l__diaa_gpfr_typographical_variant_str,
typographical-variant .value_required:n = true,
typographical-variant .initial:n = default,
}
% \getPolyFromRow will temporarily store the result in this variable. This
% allows us not to lose the result when the group started for \keys_set:nn
% ends (if the user chose to perform a local assignment, this must be done
% after closing that group).
\tl_new:N \g__diaa_gpfr_result_tl
% Options, macro for result, key, datafile label
\NewDocumentCommand \getPolyFromRow { O{} m m m }
{
\group_begin:
\keys_set:nn { diaa / getPolyFromRow } {#1}
% Globally define _gfunc function aliases that perform global or local
% assignments depending on \l__diaa_gpfr_global_assignment_bool. They
% will be used *after* we close the current group.
\bool_set_true:N \l__diaa_gpfr_dtfa_global_aliases_bool
\__diaa_gpfr_define_tl_func_aliases:
% Store the result in \g__diaa_gpfr_result_tl for now.
\bool_set_true:N \l__diaa_gpfr_global_assignment_bool
\diaa_get_poly_from_row:Nnn \g__diaa_gpfr_result_tl {#3} {#4}
\group_end:
% Use the globally-defined aliases to perform the user-chosen (local or
% global) kind of assignment.
\__diaa_clear_gfunc:N #2 % make sure the tl var #2 is defined
\__diaa_set_eq_gfunc:NN #2 \g__diaa_gpfr_result_tl % set it
}
% True to globally define the aliases and give them _gfunc names rather than
% _func
\bool_new:N \l__diaa_gpfr_dtfa_global_aliases_bool
\cs_new_protected:Npn \__diaa_gpfr_define_tl_func_aliases:
{
\bool_if:NTF \l__diaa_gpfr_global_assignment_bool
{
\__diaa_gpfr_define_alias:nnN { clear } { N } \tl_gclear_new:N
\__diaa_gpfr_define_alias:nnN { set_eq } { NN } \tl_gset_eq:NN
\__diaa_gpfr_define_alias:nnN { put_right } { Nn } \tl_gput_right:Nn
}
{
\__diaa_gpfr_define_alias:nnN { clear } { N } \tl_clear_new:N
\__diaa_gpfr_define_alias:nnN { set_eq } { NN } \tl_set_eq:NN
\__diaa_gpfr_define_alias:nnN { put_right } { Nn } \tl_put_right:Nn
}
}
% Locally or globally define an alias for a function. The alias is defined
% globally with a gfunc name if \l__diaa_gpfr_dtfa_global_aliases_bool is true.
%
% #1: stem such as “clear”, “put_right”, etc.
% #2: signature of the alias (e.g., “Nn”)
\cs_new_protected:Npn \__diaa_gpfr_define_alias:nnN #1#2
{
\bool_if:NTF \l__diaa_gpfr_dtfa_global_aliases_bool
{ \cs_gset_eq:cN }
{ \cs_set_eq:cN }
{
__diaa_#1_
\bool_if:NT \l__diaa_gpfr_dtfa_global_aliases_bool { g }
func:#2
}
}
\int_new:N \l__diaa_gpfr_degree_int
\tl_new:N \l__dia_gpfr_row_values_tl
\cs_generate_variant:Nn \__diaa_put_right_func:Nn { Nx }
\cs_generate_variant:Nn \__diaa_get_poly_from_row_append_monomial:Nnn { NnV }
% Macro for result, key, datafile label
\cs_new_protected:Npn \diaa_get_poly_from_row:Nnn #1#2#3
{
% Locally define function aliases that perform global or local assignments
% depending on \l__diaa_gpfr_global_assignment_bool: \__diaa_clear_func:Nn,
% \__diaa_put_right_func:Nn, etc.
\bool_set_false:N \l__diaa_gpfr_dtfa_global_aliases_bool
\__diaa_gpfr_define_tl_func_aliases:
% Retrieve the coefficients
\prop_get:cnN { g__diaa_csv_#3_prop } {#2} \l__dia_gpfr_row_values_tl
% Let's put (1 + degree) for now in this int variable.
\int_zero:N \l__diaa_gpfr_degree_int
\tl_map_inline:Nn \l__dia_gpfr_row_values_tl
{
\tl_if_empty:nT {##1} { \tl_map_break: }
\int_incr:N \l__diaa_gpfr_degree_int
}
\__diaa_clear_func:N #1 % initialize #1 as a tl var if necessary
\bool_set_false:N \l_tmpa_bool % true: add + operator if next coeff is > 0
\tl_map_inline:Nn \l__dia_gpfr_row_values_tl % loop over the coefficients
{
% Degree of the monomial we're about to output
\int_decr:N \l__diaa_gpfr_degree_int
% Early termination condition if the row is not full of coefficients
\int_compare:nNnT { \l__diaa_gpfr_degree_int } < { 0 }
{ \tl_map_break: }
\fp_compare:nNnF {##1} = { 0 }
{
% Insert a + operator if necessary
\bool_if:NTF \l_tmpa_bool
{
\fp_compare:nNnT {##1} > { 0 }
{ \__diaa_put_right_func:Nn #1 { + } }
}
{ \bool_set_true:N \l_tmpa_bool }
% Insert the monomial
\__diaa_get_poly_from_row_append_monomial:NnV #1 {##1}
\l__diaa_gpfr_variable_name_tl
}
}
}
\msg_new:nnn { diaa } { gpfr-unknown-typo-variant }
{ Unknown~typographical~variant~for~\token_to_str:N \getPolyFromRow :~`#1'. }
\cs_generate_variant:Nn \msg_error:nnn { nnV }
% Macro, coefficient, variable name
\cs_new_protected:Npn \__diaa_get_poly_from_row_append_monomial:Nnn #1#2#3
{
\str_case_e:nnF { \l__diaa_gpfr_typographical_variant_str }
{
{ default } { \tl_set:Nn \l_tmpa_tl { #2 \times #3 ^ } }
{ with-braces } { \tl_set:Nn \l_tmpa_tl { #2 \times {#3} ^ } }
}
{
\msg_error:nnV { diaa } { gpfr-unknown-typo-variant }
\l__diaa_gpfr_typographical_variant_str
}
\__diaa_put_right_func:Nx #1
{
\int_case:nnF { \l__diaa_gpfr_degree_int } % depending on the degree...
{
{ 0 } { \exp_not:n {#2} } % degree 0 → only the coefficient
{ 1 } { \exp_not:n { #2 \times #3 } }
}
{ % Other degrees
\exp_not:V \l_tmpa_tl % use the selected variant
% Use braces in case the exponent has several digits
{ \int_use:N \l__diaa_gpfr_degree_int }
}
}
}
\ExplSyntaxOff
\begin{document}
\ReadCSV{mydata}{test.csv}
\getPolyFromRow{\firstPoly}{First}{mydata}%
The first polynom is $\firstPoly$.
\getPolyFromRow[variable=v]{\secondPoly}{Second}{mydata}%
The second polynom is $\secondPoly$.
\getPolyFromRow[variable=(U+V)]{\thirdPoly}{Third}{mydata}%
The third polynom is $\thirdPoly$.
{% Open a group and perform a global assignment
\getPolyFromRow[global-assignment, variable=V_x]{\fourthPoly}{Fourth}{mydata}%
}%
This one (\verb|\fourthPoly|) was assigned globally: $\fourthPoly$.
\getPolyFromRow[global-assignment, variable=V_x,
typographical-variant=with-braces]{\fourthPoly}{Fourth}{mydata}%
Typographical variant with braces (usually inferior): $\fourthPoly$.
\end{document}