动态条件变量

动态条件变量

我正在尝试创建由一组条件决定的先验未知长度的文档。我正在使用 Python 生成 LaTeX 变量,包括条件变量。在变量 LaTeX 文件中,我有类似以下内容:

\newcommand{\VariableList}{VariableOne,VariableTwo}
\newcommand{\VariableOneSubOne}{SomeValueOne}
\newcommand{\VariableOneSubTwo}{SomeOtherValueOne}
\newif\ifVariableOneCondOne
\VariableOneCondOnetrue
\newcommand{\VariableTwoSubOne}{SomeValueTwo}
\newcommand{\VariableTwoSubTwo}{SomeOtherValueTwo}
\newif\ifVariableTwoCondOne
\VariableTwoCondOnefalse

变量数量未知。我循环遍历每个变量,并有一些包含由变量动态定义的值的文本。

\foreach \n in \VariableList{
Here is some text with \inputnum{\n}{SubOne} and \inputnum{\n}{SubTwo}.
}

我定义的地方:

\newcommand{\inputnum}[2]{\expandafter\csname #1#2\endcsname}

我如何定义类似的命令来利用上面定义的条件变量?例如,我尝试过:

\newcommand{\inputcondnum}[2]{\expandafter\csname if#1#2\endcsname}

使用宏将替换的逻辑

\inputcondnum{\n}{CondOne} 

以下内容

\ifVariableOneCondOne

但这似乎不起作用。关于如何使用这些动态生成的条件变量有什么建议吗?

这是一个最小的例子:

\documentclass{article}
\usepackage{pgffor}

% Command to generate variables
\newcommand{\inputnum}[2]{\expandafter\csname #1#2\endcsname}
\newcommand{\inputcondnum}[2]{\expandafter\csname if#1#2\endcsname}

% Variable definitions
\newcommand{\VariableList}{VariableOne,VariableTwo}
\newcommand{\VariableOneSubOne}{SomeValueOne}
\newcommand{\VariableOneSubTwo}{SomeOtherValueOne}
\newif\ifVariableOneCondOne
\VariableOneCondOnetrue
\newcommand{\VariableTwoSubOne}{SomeValueTwo}
\newcommand{\VariableTwoSubTwo}{SomeOtherValueTwo}
\newif\ifVariableTwoCondOne
\VariableTwoCondOnefalse


\begin{document}

\foreach \n in \VariableList{
Here is some text with \inputnum{\n}{SubOne} and \inputnum{\n}{SubTwo}. 

\inputcondnum{\n}{CondOne} Include this text if true \else Include this text if false. \fi
}
\end{document} 

答案1

通常最好避免这个问题,但你可以让它工作

\documentclass{article}
\usepackage{pgffor}

% Command to generate variables
\newcommand{\inputnum}[2]{\expandafter\csname #1#2\endcsname}
\newcommand{\inputcondnum}[2]{\expandafter\csname if#1#2\endcsname}

% Variable definitions
\newcommand{\VariableList}{VariableOne,VariableTwo}
\newcommand{\VariableOneSubOne}{SomeValueOne}
\newcommand{\VariableOneSubTwo}{SomeOtherValueOne}
\newif\ifVariableOneCondOne
\VariableOneCondOnetrue
\newcommand{\VariableTwoSubOne}{SomeValueTwo}
\newcommand{\VariableTwoSubTwo}{SomeOtherValueTwo}
\newif\ifVariableTwoCondOne
\VariableTwoCondOnefalse


\begin{document}

\foreach \n in \VariableList{
Here is some text with \inputnum{\n}{SubOne} and \inputnum{\n}{SubTwo}. 

\iftrue\csname fi\endcsname\inputcondnum{\n}{CondOne} Include this text if true \else Include this text if false. \fi
}
\end{document}

问题是 TeX 跳过了\if....\fi 构造,但它需要\if...同时查看,因为它在跳过“错误”部分时不会进行扩展。

还请注意\expandafter

\newcommand{\inputnum}[2]{\expandafter\csname #1#2\endcsname}
\newcommand{\inputcondnum}[2]{\expandafter\csname if#1#2\endcsname}

在第一种情况下,因为\csname无论如何都会扩展其内容,所以强制提前扩展\expandafter会导致构造相同的名称。在第二种情况下,\expandafter由于不可i扩展,因此什么也不做。

答案2

重新提出这个老问题是为了留下一个更清晰的解决方案,仅供后人参考。

如果出于某种原因,您致力于构造\csname if...\endcsname(例如,如果您需要传递已定义的条件的名称),那么比黑客更干净的解决方案\iftrue\csname fi\endcsname\inputcondnum...就是将整个\if...\fi构造简单地放在宏中。

\csname if...\endcsname当你的条件语句嵌套在另一个条件语句中时,就会出现问题——在本例中,是一个控制\foreach循环的隐藏条件语句。为了详细阐述 David 的回答,在执行条件语句时,TeX 会进行一些记录来跟踪嵌套的条件\if...\fi语句。如果条件语句为假,它会跳到下一个\fi(或下一个\else),但它需要知道哪个 \fi跳转到。当跳过的文本包含第二个时\if...\fi,它会记录下来,并确保继续越过内部\fi并继续跳转到外部\fi然而,它在寻找 时不会执行任何扩展\fi。因此,当 内部\if...隐藏在另一个宏(如\csname...\endcsname)中,但\fi仍然在视图中时,它的簿记就会被打乱,一切都会变得混乱。

解决方案是确保\if... 匹配\fi两个都隐藏在宏中,确保其中一个永远不会在没有另一个的情况下出现。对于您的情况,您可以将最小示例修改为如下内容(略作格式化以提高可读性):

\documentclass{article}
\setlength{\parindent}{0pt}\setlength{\parskip}{10pt} %readability
\usepackage{pgffor}

% Command to generate variables
\newcommand{\inputnum}[2]{\csname #1#2\endcsname}
\newcommand{\inputcondnum}[2]{\csname if#1#2\endcsname}

% Variable definitions
\newcommand{\VariableList}{VariableOne,VariableTwo}

\newcommand{\VariableOneSubOne}{SomeValueOne}
\newcommand{\VariableOneSubTwo}{SomeOtherValueOne}
\newcommand{\VariableTwoSubOne}{SomeValueTwo}
\newcommand{\VariableTwoSubTwo}{SomeOtherValueTwo}

\newif\ifVariableOneCondOne
\newif\ifVariableTwoCondOne
\VariableOneCondOnetrue
\VariableTwoCondOnefalse

%COMMAND TO TEST CONDITIONAL AND EXECUTE DESIRED CODE
\newcommand{\testcondnum}[4]{\inputcondnum{#1}{#2} #3 \else #4 \fi}

\begin{document}

%A simple implementation

{\bfseries Simple}:

\foreach \n in \VariableList{%
    \texttt{\textbackslash n} is \n.\\%
    Here is some text with \inputnum{\n}{SubOne} and \inputnum{\n}{SubTwo}. \\%
    \testcondnum{\n}{CondOne}{Include this text if true.}{Include this text if false.}

}

%If you want vary what's going on inside the conditional,
%re-define a macro on each pass through the loop with the
% relevant code to execute. You'll probably want to define 
%it with \def here, since \def doesn't care about overwriting 
%old commands. With \newcommand and \renewcommand, you'd need
%to worry about using one on the first pass and the other 
%on subsequent passes.

%Of course, you could also just keep feeding the "Include 
%this..." bits straight into testcondnum, but for more 
%complicated code, using macros will probably be easier.

{\bfseries Dynamic}:

\foreach \n in \VariableList{    
    \def\dothisiftrue{Include this text if \n CondOne is true.}
    \def\dothisiffalse{Include this text if \n CondOne is false.}  
    \texttt{\textbackslash n} is \n.\\%
    Here is some text with \inputnum{\n}{SubOne} and \inputnum{\n}{SubTwo}. \\%
    \testcondnum{\n}{CondOne}{\dothisiftrue}{\dothisiffalse}

}

\end{document}

编译结果:

在此处输入图片描述

相关内容