以下是我尝试定义的一些宏(基于这个问题):
\odef{foo}{bar}
foo
将定义一个具有名称和值的“对象”bar
。\objRef{foo}
将插入“对象”的值foo
。
这些宏应该允许我引用定义的变量任何地方在我的文档中。例如,执行以下操作:
Lorem ipsum dolor \objRef{sentence-Ends/lipsum}.
% INSERT OTHER PARTS OF MY DOCUMENT HERE (CHAPTERS, SECTIONS, FIGURES, TABLES, ETC.)
Defining variables now... \odef{sentence-Ends/lipsum}{sit amet} Done!
应该产生
Lorem ipsum 痛苦???。
现在定义变量...完成!
在第一次运行 LaTeX 之后
Lorem ipsum dolor sit amet。
现在定义变量...完成!
第二次运行后。
我在 objectref.sty 中编写了此代码,但它并未按预期工作——???
我的日志文件中总是出现页面和未定义警告。
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{objectref}[Create and reference custom variables in LaTeX documents]
\def\odef#1#2{\immediate\write\@auxout{\expandafter\def \csname obj:#1\endcsname {#2}}}
\def\objRef#1{\ifcsname obj:#1\endcsname \csname obj:#1\endcsname \else ??? \PackageWarning{objectref}{Object #1 undefined on input line \the\inputlineno.}\fi}
除其他外,我编译文档时生成的.aux 文件包含:
\def \obj:sentence-Ends/lipsum {sit amet}
哪个应该意味着一切都会正常工作(但事实并非如此)。
我的代码有什么问题?我该如何修复它?
答案1
主要问题是您应该使用\gdef
而不是\def
,因为.aux
文件是在组内读取的。
第二个问题:使用你的代码你会得到
\def \obj:sentence-Ends/lipsum {...}
在.aux
文件中,但是这定义了\obj
。
第三个问题:如果你这样做
\odef{test}{\'amet}
该.aux
文件将包含垃圾(尝试一下)。
第四个问题:如果您打算\odef
在段落中间说话,那么您在输出中就会得到虚假的空格。
建议的解决方案。
不要在文件中写入\def
nor并使替换文本不扩展。也可以使用and 。\gdef
.aux
\@bsphack
\@esphack
\documentclass{article}
\makeatletter
\newcommand{\odef}[2]{%
\@bsphack
\immediate\write\@auxout{\string\objectref@def{#1}{\unexpanded{#2}}}%
\@esphack
}
\newcommand{\objectref@def}[2]{\global\@namedef{obj:#1}{#2}}
\newcommand{\objRef}[1]{%
\ifcsname obj:#1\endcsname
\csname obj:#1\endcsname
\else
???%
\PackageWarning{objectref}{Object #1 undefined on input line \the\inputlineno.}%
\fi
}
\makeatother
\begin{document}
Lorem ipsum dolor \objRef{sentence-Ends/lipsum}
Defining variables now... \odef{sentence-Ends/lipsum}{sit \'amet} Done!
Defining variables now... Done!% added line to check spaces
\end{document}
该.aux
文件将
\relax
\objectref@def{sentence-Ends/lipsum}{sit \'amet}
\gdef \@abspage@last{1}
输出为
如果我注释掉\@bsphack
并且\@esphack
,我得到
错误的间距很明显。
不同版本中第二个参数\odef
在文件中安全扩展.aux
;安全意味着重音和其他危险命令不需要受到保护。
这是通过 的更强大的功能实现的expl3
,特别\text_expand:n
是它精确地完成了我们需要的工作。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\odef}{mm}
{
\use:c { @bsphack }
\iow_now:cx { @auxout } { \token_to_str:N \objectrefdef { #1 } { \text_expand:n { #2 } } }
\use:c { @esphack }
}
\NewDocumentCommand{\objectrefdef}{mm}
{
\prop_gput:Nnn \g_benz_objectref_prop { #1 } { #2 }
}
\prop_new:N \g_benz_objectref_prop
\NewExpandableDocumentCommand{\objRef}{m}
{
\prop_if_in:NnTF \g_benz_objectref_prop { #1 }
{
\prop_item:Nn \g_benz_objectref_prop { #1 }
}
{
???
\PackageWarning{objectref}{Object~#1~undefined}
}
}
\ExplSyntaxOff
\newcounter{Counter}
\begin{document}
Lorem ipsum dolor \objRef{sentence-Ends/lipsum}
Defining variables now... \odef{sentence-Ends/lipsum}{sit \'amet} Done!
Defining variables now... Done!% added line to check spaces
\stepcounter{Counter}
\odef{Name with space}{The counter value hêr\'e is \theCounter}
\stepcounter{Counter} % now 2
\objRef{Name with space}
\end{document}
请注意,第一个参数中的空格被尊重,并且使用时间的当前\odef
值。Counter
\odef
答案2
你没有给出最小的例子,所以我的回答只是理论上的,没有经过检验。定义\sdef
宏的用法:
\sdef{text}{body}
将其定义\csname text\endcsname
为主体。并在文件中使用它.aux
。因此:
\def\sdef#1{\expandafter\gdef\csname#1\endcsname}
\def\odef#1#2{\immediate\write\@auxout{\string\sdef{obj:#1}{#2}}}
\def\objRef#1{\ifcsname obj:#1\endcsname \csname obj:#1\endcsname \else ??? \PackageWarning{objectref}{Object #1 undefined on input line \the\inputlineno.}\fi}