使用 CSV 文件驱动自定义宏

使用 CSV 文件驱动自定义宏

背景

我正在尝试弄清楚为什么附加的 MWE 不起作用。我的自定义宏在环境内部和外部reqUser使用时都能正常工作。只有在命令之外时才有效。我不明白我做错了什么。xstringcsvsimpleexpl3csvsimple

我正在创建一个模板,供我的大学将来使用。此特定项目的目的是为将来处理超大文档的学生提供一种更简单的方法来指定工程要求。在制作此宏之前,每个项目都手动编码到宏中,然后复制过来以创建要求列表。这非常混乱,而且很难理解。

问题

编码过程中发生了什么expl3

  • \checkboxYesNoOld,在里面\reqUserXstring,在里面正常工作\csvreader
  • \checkboxYesNo,里面\reqUserExpl,里面无法正常工作\csvreader

csvsimple对于 CSV 驱动的宏命令系列,是否使用“最佳”方式?

  • etoolboxmathtoolspgfplots也加载

平均能量损失

\documentclass{article}
\usepackage{siunitx}
\usepackage{booktabs}
\usepackage{tabularray}
\usepackage{tikz}
\usepackage{xstring}
\usepackage{csvsimple}

\UseTblrLibrary{booktabs} 


\begin{filecontents*}{data.csv}
id,name,description,remarks,parent,verification
M-01, Req Name 1, {A description with numbers and units: \qty{50}{\m}}, {Some remarks with an angle \ang{;;1}} ,-,tir
M-02, Req Name 2, A short description, Some remarks, The Parent Requirement, ai
\end{filecontents*}

\newcommand{\checkboxBox}[1]
  {%
    \begin{tikzpicture}[scale=1, line width=1.0pt]
      \draw (0,0) rectangle (1.5ex, 1.5ex) #1;
    \end{tikzpicture}%
  }

\newcommand{\checkYes}{%
  \checkboxBox
    {%
      ( 0.3ex,  0.3ex) -- +
      ( 0.9ex,  0.9ex)
      ( 0.3ex,  1.2ex) -- + 
      ( 0.9ex, -0.9ex)
    }%
}

% Creates Unchecked Checkbox
\newcommand{\checkNo}{\checkboxBox{}}

% Macro to decide if a checked or unchecked box is needed
\ExplSyntaxOn
\prg_generate_conditional_variant:Nnn \str_if_in:nn {ee} { TF, T, F }
\NewDocumentCommand{\checkboxYesNo}{mm}
  {
    \str_if_in:eeTF { \str_foldcase:n { #2 } } { \str_foldcase:n { #1 } }
      {\checkYes}
      {\checkNo}
  }
\ExplSyntaxOff

\newcommand{\checkboxYesNoOld}[2]{
  %% #1--Find This;  #2--Search This List
  %% Outputs a Checked or Unchecked box 
  \lowercase{\def\myList{#2}}%
  \lowercase{\def\findMe{#1}}%
  \IfSubStr{\myList}{\findMe}{\checkYes}{\checkNo}%
  % \IfSubStr{\myList}{\findMe}{Yes \findMe - \myList}{No \findMe - \myList}%
}

% * EXAMPLE OF HOW TO USE THIS COMMAND BELOW
% \reqUser{Req Name}    % Req Name
%     {Req ID}          % Req ID
%     {Wording}         % Wording
%     {Remarks}         % Remarks
%     {Parent}          % Parent
%     {t a i r}         % Verification - Test(t), Analysis(a), Insp(i), Review(r)
\newcommand{\reqUserXstring}[6]{% 
  \begin{tblr}{
    width    =  0.99\textwidth, 
    colspec  =  {>{\small}h{60pt}  X}
    }

    \toprule
    \textbf{Req Name} & \textbf{#2} \\

    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Req ID       &  #1 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Requirement  &  #3 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Remarks      &  #4 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Parent       &  #5 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}

    Verification &
      \small
      \checkboxYesNoOld{t}{#6} Test \hfill
      \checkboxYesNoOld{a}{#6} Analysis \hfill
      \checkboxYesNoOld{i}{#6} Inspection \hfill
      \checkboxYesNoOld{r}{#6} Review-of-Design \\

    \bottomrule
  \end{tblr}
}

\newcommand{\reqUserExpl}[6]{% 
  \begin{tblr}{
    width    =  0.99\textwidth, 
    colspec  =  {>{\small}h{60pt}  X}
    }

    \toprule
    \textbf{Req Name} & \textbf{#2} \\

    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Req ID       &  #1 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Requirement  &  #3 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Remarks      &  #4 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}
    Parent       &  #5 \\
    \cmidrule[r]{1-1} \cmidrule[l]{2-2}

    Verification &
      \small
      \checkboxYesNo{t}{#6} Test \hfill
      \checkboxYesNo{a}{#6} Analysis \hfill
      \checkboxYesNo{i}{#6} Inspection \hfill
      \checkboxYesNo{r}{#6} Review-of-Design \\

    \bottomrule
  \end{tblr}
}

\begin{document}

Non-CSV Command:

\reqUserXstring{M-01}{Req Name 1}{A description with numbers and units: \qty{50}{\m}}{Some remarks with an angle \ang{;;1}}{-}{tir}
\reqUserExpl{M-02}{Req Name 2}{A short description}{Some remarks}{The Parent Requirement}{ai}

xstring-CSV Command:

\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{\bigbreak \reqUserXstring{\idNum }{\idName}{\desc}{\remarks}{\parent}{\verf}}

expl3-CSV Command:

\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{\bigbreak \reqUserExpl{\idNum }{\idName}{\desc}{\remarks}{\parent}{\verf}}

\end{document}

答案1

在您的定义中\checkboxYesNo找到这条线
\str_if_in:eeTF { \str_foldcase:n { #2 } } { \str_foldcase:n { #1 } }

我的猜测是,在扩展之前\str_if_in:eeTF触发扩展,并且被扩展,因此大小写折叠和字符串化被应用于控制字标记,而不是形成其扩展的标记。\str_foldcase:n#1#2\verf


\cs_generate_variant:Nn \str_foldcase:n { e }如果我的猜测是正确的,那么可能可以通过和使用\str_foldcase:e而不是来解决这个问题\str_foldcase:n

\checkboxYesNo或者在try的定义内
\str_if_in:eeTF { \exp_args:Ne \str_foldcase:n { #2 } } { \exp_args:Ne \str_foldcase:n { #1 } }

这样,在触发 的扩展之前,带有 的-type -arguments 的e-expansion会触发的扩展,而后者又会触发 的-type参数的 -expansion 。在执行 时,对的-type 参数进行 -expansion的结果又会是的参数。\str_if_in:eeTFe\str_foldcase:n\exp_args:Nee\exp_args:Neee\exp_args:Nee\str_foldcase:n\str_foldcase:n

如果你不喜欢完全扩展/完全评估#1/#2也许——而不是上面介绍的技巧——比如

\ExplSyntaxOn
\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{%
  \bigbreak 
  \exp_args:Nno \use:n 
                {\reqUserExpl{\idNum }{\idName}{\desc}{\remarks}{\parent}}%
                {\verf}%
}
\ExplSyntaxOff

,其中 的第六个参数将是的-type-argument\reqUserExpl的第一个标记的顶层扩展,即 的顶层扩展,\exp_args:Nnoo{\verf}\verf

代替

\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{\bigbreak \reqUserExpl{\idNum }{\idName}{\desc}{\remarks}{\parent}{\verf}}

成功了。

为了获得其他参数的第一个标记的顶层扩展\reqUserExpl,可以在的参数中重复应用-trick——使用以下代码片段示例,您可以获得和的顶层扩展:\exp_args:Nno \use:n{...}{⟨stuff whose first token shall be expanded once⟩}\use:n\verf\parent

\ExplSyntaxOn
\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{
  \bigbreak 
  \exp_args:Nno \use:n 
                {
                   \exp_args:Nno \use:n
                   {\reqUserExpl{\idNum }{\idName}{\desc}{\remarks}}
                   {\parent}
                }
                {\verf}
}
\ExplSyntaxOff

如果你喜欢不那么麻烦的东西,你可以\exp:args:Ne与结合起来\exp_not:o。用粗略的术语来表达:在下面,你将获得第一个标记的顶层扩展,其中包含 的所有参数\reqUserExpl

\ExplSyntaxOn
\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{%
  \bigbreak 
  \exp_args:Ne  \use:n {
                         \exp_not:n{\reqUserExpl}
                         {  \exp_not:o{\idNum}  }
                         {  \exp_not:o{\idName}  }
                         {  \exp_not:o{\desc}  }
                         {  \exp_not:o{\remarks}  }
                         {  \exp_not:o{\parent}  }
                         {  \exp_not:o{\verf}  }
                       }
}
\ExplSyntaxOff

您可能还可以使用\exp_last_unbraced:Ne

\ExplSyntaxOn
\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{%
  \bigbreak 
  \exp_last_unbraced:Ne \reqUserExpl 
                        {
                           {  \exp_not:o{\idNum}  }
                           {  \exp_not:o{\idName}  }
                           {  \exp_not:o{\desc}  }
                           {  \exp_not:o{\remarks}  }
                           {  \exp_not:o{\parent}  }
                           {  \exp_not:o{\verf}  }
                        }
}
\ExplSyntaxOff

如果您不喜欢/不熟悉 expl3-tools 的扩展控制,并且出于某种原因更喜欢坚持使用更传统的扩展技巧,您可以在扩展第一个参数的第一个标记后让 TeX 交换/传递宏参数。在下面的代码示例片段中,\reqUserExpl的第六个参数将是的顶层扩展\verf

\newcommand\PassFirstToSecond[2]{#2{#1}}%
\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{%
  \bigbreak
  \expandafter\PassFirstToSecond\expandafter{\verf}{%
    \reqUserExpl{\idNum }{\idName}{\desc}{\remarks}{\parent}%
  }%
}

这个技巧可以重复应用,在要交换/传递的第二个参数中。在下面的代码示例片段中,\reqUserExpl的第六个参数将是 的顶层扩展,\verf\reqUserExpl第五个参数将是 的顶层扩展\parent

\newcommand\PassFirstToSecond[2]{#2{#1}}%
\csvreader[]{data.csv}
{1=\idNum,2=\idName,3=\desc,4=\remarks,5=\parent,6=\verf}
{%
  \bigbreak
  \expandafter\PassFirstToSecond\expandafter{\verf}{%
    \expandafter\PassFirstToSecond\expandafter{\parent}{%
      \reqUserExpl{\idNum }{\idName}{\desc}{\remarks}%
    }%
  }%
}

相关内容