要模拟变量求值的前瞻,请运行两次包含宏的文本块。如何在第一次传递中抑制文本输出?

要模拟变量求值的前瞻,请运行两次包含宏的文本块。如何在第一次传递中抑制文本输出?

我正在为我的朋友们写一个小补充,我们使用 GURPS 桌面角色扮演游戏系统。该系统使用积分池来购买角色的各个方面。我希望在统计块的开头显示角色的总积分,但为了计算总积分,我在统计块中插入了计数器。

由于 LaTeX 实际上没有预见到这种事情(因此需要辅助文件和 co),我只想运行 stat 块两次,但抑制第一次传递的输出。

我意识到这有点“低劣”,我应该只使用数据创建一个本地“前言”设置,但是字符太多了,我正在从外部工具生成 statblock 并在其间进行一些处理。

现在,通常我会在那里计算总数,但有一些复杂的情况我不想在这里详细说明,我会手动调整一些成本等等。

无论如何。问题的核心是,是否可以在不打印任何文本的情况下对 TeX 进行求值,而只对变量和命令进行求值?

如果是的话,其命令是什么?

我基本上是在询问类似 \makeatletter 和 \makeatother 的内容。

围绕块的宏如下

\documentclass{article}
\mycounter
\begin{document}
\suppressPrinting %fictitious/unknown macro I am asking for here
My total is \themycounter 
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\resumePrinting

My total is \themycounter % now holds 150
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\setcounter{mycounter}{0}
\end{document}

我想我的问题基本上是重复的: 隐藏宏的输出

但那已经是九年前的事了。这方面有什么变化吗?

答案1

在修复示例中不相关的错误后,您可以在框中进行第一遍。

在此处输入图片描述

\documentclass{article}
\newcounter{mycounter}
\begin{document}

\begin{lrbox}{0}
My total is \themycounter\ 
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\end{lrbox}

My total is \themycounter\ % now holds 150
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\setcounter{mycounter}{0}
\end{document}

或者只需设置一次文本,然后使用标准\label/\ref机制通过文件处理前向引用aux。这需要两次 LaTeX 传递。

\documentclass{article}
\newcounter{mycounter}
\begin{document}


My total is \ref{thistot} % now holds 150
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\addtocounter{mycounter}{-1}\refstepcounter{mycounter}\label{thistot}
\setcounter{mycounter}{0}
\end{document}

答案2

正如我所评论的,我的回答是LaTeX3:以优雅的方式向前引用具有“未来”值的计数器可能会提供一种解决方法,减轻两次输入数据的需要。

它使用一个令牌循环来评估环境中的令牌pointtracker,以搜索与\addtopoints调用相对应的点分配。然后它打印出环境内容,将分配的点总数放在环境的开头。

虽然这里没有显示(参见参考答案),但环境可能是嵌套的。

\documentclass{article}
\usepackage{tokcycle}[2021-05-27]
\usepackage{environ}
\newcounter{pointcount}
\newcommand\addtopoints[1]{(\textit{#1 point}%
  \ifnum#1=1\relax\else\textit{s}\fi)}
\def\z{\tcpop\Q\addtocounter{pointcount}{\Q}\tcpushgroup{\Q}}
\NewEnviron{pointtracker}[2][points]{%
  \par\bigskip\resettokcycle
  \setcounter{pointcount}{0}%
  \Macrodirective{\addcytoks{##1}\tctestifx{\addtopoints##1}{\z}{}}%
  \def\tmp{\tokencyclexpress{\Large\bfseries #2: \thepointcount{} #1}}%
  \expandafter\tmp\BODY\endtokencyclexpress
}
\begin{document}
\begin{pointtracker}[total points]{
Sum of Cool Abilities} % now holds 150

Cool ability A \addtopoints{50}

Cool ability B \addtopoints{50}

Cool ability C \addtopoints{50}
\end{pointtracker}
\end{document}

在此处输入图片描述

上面,我展示了单个点值的短语(单词和数字)表达。为了匹配更简单的东西,按照 OP 的代码,只需简化 的定义\addtopoints,例如,

\newcommand\addtopoints[1]{[\textit{#1}]}

答案3

例如,看看

My total is \themycounter 
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}

出现以下问题:

  • 您希望在生成的 .pdf 文件中看到什么\themycounter?(显然 - 以十进制表示法,使用阿拉伯数字 - 计数器mycounter在某一时刻的值。哪个时刻?)
  • 和之间50的相关性是什么?[50]50\addtocounter{mycounter}{50}

如果您认为可以轻松地让 TeX 执行相同的标记序列两次,但一次抑制将内容输出到输出文件/.pdf 文件,那么您可能会忽略一些有趣的问题。

让我们想象一下,除了输出到 .pdf 文件之外,这个标记序列还执行其他操作。然后,所有这些其他操作都执行两次。您不一定希望这样。例如,您不希望计数器全局递增两次。您不希望这样的事情\immediate\write执行两次。您不希望随机数生成器执行两次,第二次提供的值与第一次提供的值不同。但即使您使用内容未排版的框寄存器,也可能发生这种情况。

所以你需要一个机制来指定

  • 第一遍要做哪些事情(计算“变量”的值)。
  • 第二遍要做哪些事情(将要排版的内容传送到输出文件/.pdf 文件)。
  • 当前传递是否被视为第一传递=计算传递。
  • 当前传递是否被视为第二传递=传递至 output-file/.pdf-file-pass。

因此,你最终会得到一种将事实上的计算与输出分开的机制——当然你可以轻松地做到这样的事情:

\documentclass{article}
\newcounter{mycounter}
\newif\ifcalculate
\newif\ifdelivertooutputfile

\newcommand\DoCalculationsOnly{\calculatetrue\delivertooutputfilefalse}
\newcommand\DoDeliverToOutputfileOnly{\calculatefalse\delivertooutputfiletrue}

\begin{document}

\DoCalculationsOnly
\ifdelivertooutputfile\noindent My total is \themycounter\\\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\fi
\ifcalculate\addtocounter{mycounter}{50}\fi

\DoDeliverToOutputfileOnly
\ifdelivertooutputfile\noindent My total is \themycounter\\\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\fi
\ifcalculate\addtocounter{mycounter}{50}\fi

% \setcounter{mycounter}{0}
% In case the package hyperref is in use resetting counters leads to
% uniqueness of names of automatically created named destinations not
% being ensured any more, thus I suggest not doing this but doing
% something similar to what is done in my subsequent examples.

\end{document}

在此处输入图片描述

我想 - 正如 Ulrike Fischer 所说 - 您可能可以轻松使用交叉引用机制:

\documentclass{article}
\usepackage{hyperref}

\newcounter{mycounter}
\newcommand\mycountermacro{0}
\newcommand\resetmycounter{\gdef\mycountermacro{0}}
\makeatletter
\renewcommand\themycounter{\@arabic{\mycountermacro}}
\makeatother

\newcommand\AddAbility[2]{%
  \\%
  \xdef\mycountermacro{\number\numexpr\mycountermacro+#2\relax}%
  \refstepcounter{mycounter}%
  #1 [#2]%
}

\begin{document}

\resetmycounter
\noindent Total of character A is \ref*{TotalOfCharacterA}
\AddAbility{Cool ability of character A}{50}
\AddAbility{Another cool of character A}{40}
\AddAbility{Yet another cool ability of character A}{30}
\label{TotalOfCharacterA}

\noindent\hrulefill

\resetmycounter
\noindent Total of character B is \ref*{TotalOfCharacterB}
\AddAbility{Cool ability of character B}{5}
\AddAbility{Another cool of character B}{4}
\AddAbility{Yet another cool ability of character B}{3}
\label{TotalOfCharacterB}

\noindent\hrulefill

\resetmycounter
\noindent Total of character C is \ref*{TotalOfCharacterC}
\AddAbility{Cool ability of character C}{25}
\AddAbility{Another cool of character C}{20}
\AddAbility{Yet another cool ability of character C}{15}
\label{TotalOfCharacterC}

\end{document}

在此处输入图片描述



如果您不想只用整数计算,您可以使用一些数学库来实现类似的方法,例如 pgfmath:

\documentclass{article}
\usepackage{hyperref}
\usepackage{pgfmath}

\newcounter{mycounter}
\newcommand\mycountermacro{0}
\newcommand\resetmycounter{\gdef\mycountermacro{0}}
\renewcommand\themycounter{\mycountermacro}
\makeatletter
\newcommand\AddAbility[2]{%
  \\%
  \begingroup
  \pgfkeys{/pgf/number format/.cd,fixed,precision=2,fixed zerofill=true}%
  \pgfmathparse{\mycountermacro+#2}%
  \pgfmathroundtozerofill{\pgfmathresult}%
  \global\let\mycountermacro=\pgfmathresult
  \refstepcounter{mycounter}%
  #1 [\pgfmathparse{#2}\pgfmathroundtozerofill{\pgfmathresult}\pgfmathresult]%
  \expandafter\endgroup
  \expandafter\def\expandafter\@currentlabel\expandafter{\@currentlabel}%
}
\makeatother

\begin{document}

\resetmycounter
\noindent Total of character A is \ref*{TotalOfCharacterA}
\AddAbility{Cool ability of character A}{50.1}
\AddAbility{Another cool of character A}{40.69}
\AddAbility{Yet another cool ability of character A}{30.2}
\label{TotalOfCharacterA}

\noindent\hrulefill

\resetmycounter
\noindent Total of character B is \ref*{TotalOfCharacterB}
\AddAbility{Cool ability of character B}{5.15}
\AddAbility{Another cool of character B}{4.62}
\AddAbility{Yet another cool ability of character B}{3.22}
\label{TotalOfCharacterB}

\noindent\hrulefill

\resetmycounter
\noindent Total of character C is \ref*{TotalOfCharacterC}
\AddAbility{Cool ability of character C}{25.02}
\AddAbility{Another cool of character C}{20.06}
\AddAbility{Yet another cool ability of character C}{15.01}
\label{TotalOfCharacterC}

\end{document}

在此处输入图片描述



如果 statblock 是数据库的组件,则包数据工具可能会感兴趣。

相关内容