![要模拟变量求值的前瞻,请运行两次包含宏的文本块。如何在第一次传递中抑制文本输出?](https://linux22.com/image/439495/%E8%A6%81%E6%A8%A1%E6%8B%9F%E5%8F%98%E9%87%8F%E6%B1%82%E5%80%BC%E7%9A%84%E5%89%8D%E7%9E%BB%EF%BC%8C%E8%AF%B7%E8%BF%90%E8%A1%8C%E4%B8%A4%E6%AC%A1%E5%8C%85%E5%90%AB%E5%AE%8F%E7%9A%84%E6%96%87%E6%9C%AC%E5%9D%97%E3%80%82%E5%A6%82%E4%BD%95%E5%9C%A8%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%BC%A0%E9%80%92%E4%B8%AD%E6%8A%91%E5%88%B6%E6%96%87%E6%9C%AC%E8%BE%93%E5%87%BA%EF%BC%9F.png)
我正在为我的朋友们写一个小补充,我们使用 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 是数据库的组件,则包数据工具可能会感兴趣。