expl3:打印存储在 CSV 文件中一行中的系数的多项式

expl3:打印存储在 CSV 文件中一行中的系数的多项式

后续行动这个答案\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}

在此处输入图片描述

相关内容