正如我在其他问题中已经提到的,我正在编写一个问题/解决方案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}}