通过 \immediate\write 存储环境参数

通过 \immediate\write 存储环境参数

正如我在其他问题中已经提到的,我正在编写一个问题/解决方案package。当然,有很多,我已经取得了很大进展,在“日常”生产力中使用它来满足我的需求,但到目前为止它还没有为其他用户设计。我遇到了一些奇怪的行为,我最初以为这是我的错误使用造成的。

基本上,我使用一个父级environment,一方面负责格式化问题(可通过xkeyval键配置),另一方面是驱动程序,将解决方案(包含在类似的environment,称为“子级”)存储到外部文件中,然后在用户想要的位置读取。

现在的问题是,一旦有其他命令交给键值,这就会失败。

这是 MWE,它在\immediate\write第二次parent调用完成的过程中失败ChildOutputStyle=\YetAnotherOutputStyle

\documentclass{article}
\usepackage{xkeyval}
\usepackage{xcolor}


\newcommand{\DefaultTextStyle}[1]{%
\textbf{\textcolor{blue}{#1}}%
}%

\newcommand{\YetAnotherOutputStyle}[1]{%
\textbf{\textcolor{green}{#1}}%
}%


\newwrite\OutputFileHandle%

\makeatletter%
\define@key{FamilyA}{ChildOutputStyle}[\DefaultTextStyle]{%
\def\KVMacroChildOutputStyle{#1}%
}%

\makeatother

\newcommand{\Child}[2][]{%
\setkeys{FamilyA}{#1}%

\KVMacroChildOutputStyle{#2}%

}% End of \newcommand{\Child} %



\newcommand{\Parent}[3][]{%
\setkeys{FamilyA}{#1}%

%  Do some stuff before with 2nd arg of command ('problem')
#2\par %%%%%
%%%%
%
% Now write solution ('child') content to filehandle
\immediate\write\OutputFileHandle{%
\string\Child[#1]{#3}%
}%
}%  End of \Parent command


\begin{document}
\presetkeys{FamilyA}{ChildOutputStyle={\DefaultOutputStyle}}{}%
\immediate\openout\OutputFileHandle=\jobname.myext


\textbf{\textcolor{violet}{First 'Parent' content}}% 
\par
\Parent{One Ring To Rule Them All}{One Ring To Find Them}  % I hope, Tolkien does not mind! 

%%% This code breaks when tried to save it immediately to another file!!!!
\Parent[ChildOutputStyle=\YetAnotherOutputStyle]{When shall we three meet again}{In Thunder, lightning or in rain} % William Shakespeare will not mind ;-)
%%%%


\immediate\closeout\OutputFileHandle

\textbf{\textcolor{red}{Now 'Child' content}}% 
\par
\input{\jobname.myext} % replace it afterwards with \IncludeIfFileExists... etc.

\end{document}

编译失败并显示以下消息

! Use of \XKV@resa doesn't match its definition.
\XKV@for@n #1#2#3->\XKV@tempa@toks {#1}\edef #2{
                                                \the \XKV@tempa@toks }\ifx #...
l.57 ...t again}{In Thunder, lightning or in rain}

有什么解决方法吗(除了使用verbatim/moreverb包?)

最后的一些评论:

  • 我已经用 s 替换了\newenvironment我原始包中的语句\newcommand,以使示例更短,但我更喜欢环境风格。
  • \DefaultTextStyle和命令\YetAnotherOutputStyle只是一些“任意”命令的占位符。
  • 我省略了\AtBeginDocument打开文件和AtEndDocument 关闭文件的步骤,以使代码保持简短。

我确信其他用户也会从解决方案中受益。

答案1

最大的问题是你想传递给\write诸如\textbf或之类的命令,而\textcolor这些命令无法存活。内核有\protected@write这个功能,但没有“即时”版本。

然而,很容易将其定义为使用包 [utf8]{inputenc} 时,如何将 € 符号写入文件

您还必须确保\textcolor受到保护,因为它本身很脆弱;最简单的方法是使用以下方式定义样式\DeclareRobustCommand

\documentclass{article}
\usepackage{xkeyval}
\usepackage{xcolor}


\DeclareRobustCommand{\DefaultTextStyle}[1]{%
  \textbf{\textcolor{blue}{#1}}%
}

\DeclareRobustCommand{\YetAnotherOutputStyle}[1]{%
  \textbf{\textcolor{green}{#1}}%
}


\newwrite\OutputFileHandle

\makeatletter
\define@key{FamilyA}{ChildOutputStyle}[\DefaultTextStyle]{%
  \def\KVMacroChildOutputStyle{#1}%
}


\newcommand{\Child}[2][]{%
  \setkeys{FamilyA}{#1}
  \KVMacroChildOutputStyle{#2}%
}

%%% Helper macro
\long\def\protected@iwrite#1#2#3{%
      \begingroup
       \let\thepage\relax
       #2%
       \let\protect\@unexpandable@protect
       \edef\reserved@a{\immediate\write#1{#3}}%
       \reserved@a
      \endgroup
      \if@nobreak\ifvmode\nobreak\fi\fi
}

\newcommand{\Parent}[3][]{%
  \setkeys{FamilyA}{#1}%
  %  Do some stuff before with 2nd arg of command ('problem')
  #2\par %%%%%
  %%%%
  %
  % Now write solution ('child') content to filehandle
  \protected@iwrite\OutputFileHandle{}{%
    \string\Child[#1]{#3}%
  }%
}
\makeatother


\begin{document}
\presetkeys{FamilyA}{ChildOutputStyle={\DefaultTextStyle}}{}%
\immediate\openout\OutputFileHandle=\jobname.myext


\textbf{\textcolor{violet}{First 'Parent' content}}

\Parent{One Ring To Rule Them All}{One Ring To Find Them}  % I hope, Tolkien does not mind! 

%%% This code breaks when tried to save it immediately to another file!!!!
\Parent[ChildOutputStyle=\YetAnotherOutputStyle]{When shall we three meet again}{In Thunder, lightning or in rain} % William Shakespeare will not mind ;-)
%%%%


\immediate\closeout\OutputFileHandle

\textbf{\textcolor{red}{Now 'Child' content}}

\input{\jobname.myext} % replace it afterwards with \IncludeIfFileExists... etc.

\end{document}

在此处输入图片描述

以下是该文件的内容.myext

\Child[]{One Ring To Find Them}
\Child[ChildOutputStyle=\protect \YetAnotherOutputStyle  ]{In Thunder, lightning or in rain}

采用不同的策略\write,但伴随以下操作\unexpanded

\documentclass{article}
\usepackage{xkeyval}
\usepackage{xcolor}


\newcommand{\DefaultTextStyle}[1]{%
  \textbf{\textcolor{blue}{#1}}%
}

\newcommand{\YetAnotherOutputStyle}[1]{%
  \textbf{\textcolor{green}{#1}}%
}


\newwrite\OutputFileHandle

\makeatletter
\define@key{FamilyA}{ChildOutputStyle}[\DefaultTextStyle]{%
  \def\KVMacroChildOutputStyle{#1}%
}


\newcommand{\Child}[2][]{%
  \setkeys{FamilyA}{#1}
  \KVMacroChildOutputStyle{#2}%
}

\newcommand{\Parent}[3][]{%
  \setkeys{FamilyA}{#1}%
  %  Do some stuff before with 2nd arg of command ('problem')
  #2\par %%%%%
  %%%%
  %
  % Now write solution ('child') content to filehandle
  \immediate\write\OutputFileHandle{%
    \string\Child[\unexpanded\expandafter{#1}]{\unexpanded{#3}}%
  }%
}

\makeatother


\begin{document}
\presetkeys{FamilyA}{ChildOutputStyle={\DefaultTextStyle}}{}%
\immediate\openout\OutputFileHandle=\jobname.myext


\textbf{\textcolor{violet}{First 'Parent' content}}

\Parent{One Ring To Rule Them All}
       {One Ring To Find Them}  % I hope, Tolkien does not mind! 

%%% This code breaks when tried to save it immediately to another file!!!!
\Parent[ChildOutputStyle=\YetAnotherOutputStyle]
       {When shall we three meet again}
       {In Thunder, lightning or in rain} % William Shakespeare will not mind ;-)

\Parent[ChildOutputStyle=\DefaultTextStyle]
       {A formula}
       {\begin{math}\sqrt{2}^2=2\end{math}}

%%%%


\immediate\closeout\OutputFileHandle

\textbf{\textcolor{red}{Now 'Child' content}}

\input{\jobname.myext} % replace it afterwards with \IncludeIfFileExists... etc.

\end{document}

以下是文件中的输出.myext

\Child[]{One Ring To Find Them}
\Child[ChildOutputStyle=\YetAnotherOutputStyle ]{In Thunder, lightning or in rain}
\Child[ChildOutputStyle=\DefaultTextStyle ]{\begin {math}\sqrt {2}^2=2\end {math}}

相关内容