我正在进行一些通过自动生成文件句柄的实验\newwrite
。
我想要实现以下行为:
用户提供文件类别列表,例如提示,解决方案,问题等等,以及相应扩展的列表,比如,,
.hints
按正确的顺序(应该如何知道哪个类别属于哪个扩展,反之亦然),例如作为命令的第一个和第二个参数,。.sol
.prb
TeX
\RegisterOutputFiles
类别和扩展之间的联系存储在两个名称不同但计数器编号相同的文本标签中,基本内容在我的另一个问题中描述(已解决,详情见此处:将文本内容写为标签并使用 \nameref* 引用它们)
\RegisterOutputFiles
应该用一些好听的名字创建文件句柄,以便记住它们,比如说\HintsFile
,\SolutionsFile
等等,然后打开它们通过等等进行写入\immediate\openout\HintsFile=\jobname.hints
,所有这些都在循环中。
现在循环失败,当自定义命令\NewWrite
显示错误消息时
! Missing \endcsname inserted. <to be read again> \protect l.84 ....prb,.hints,.sol,.explain,.idea,.concepts}
我很确定,我错过了一些扩展或类似的东西,但我无法弄清楚,因为它可以\NewWrite
通过直接注入诸如Hints
等词语来工作。
这是(通常不起作用的)MWE
\documentclass{article}
\usepackage{ifthen}
\usepackage{etoolbox}
\usepackage{blindtext}
\usepackage{morewrites}
\usepackage{xcolor}
\usepackage{hyperref}%
\newrobustcmd{\NewWrite}[1]{%
\expandafter\newwrite\csname#1\endcsname%
}%
%% Later on... Create a handle from #1 and directly combine
%% it with filename #2 with \immediate\openout%
\newrobustcmd{\NewWriteOpenOut}[2]{%
\expandafter\newwrite\csname#1\endcsname%
\immediate\openout\csname #1\endcsname=#2%
}%
\makeatletter
\newcounter{pc@@filecounter}%
\newcounter{pc@@totalfilecounter}%
\newcounter{pc@@loopcounter}%
%% Hopefully only text is in #1%
\newrobustcmd{\WriteOutputFileLabel}[1]{%
\refstepcounter{pc@@filecounter}%
\immediate\write\@auxout{%
\string\newlabel{pc::outputfile::\number\value{pc@@filecounter}}{{\thesection}{\thepage}{#1}{}}%
}% End of writing to AUX file
}%
\newrobustcmd{\WriteOutputFileNameLabel}[1]{%
\refstepcounter{pc@@filecounter}%
\immediate\write\@auxout{%
\string\newlabel{pc::outputfilename::\number\value{pc@@filecounter}}{{\thesection}{\thepage}{#1}{}}%
}% End of writing to AUX file
}%
\newrobustcmd{\RegisterOutputFiles}[2]{%
%%% Other code before
%
\setcounter{pc@@filecounter}{0}%
\forcsvlist{\WriteOutputFileLabel}{#1}% Store the output file `categories` to label names
\setcounter{pc@@totalfilecounter}{\number\value{pc@@filecounter}}%
\setcounter{pc@@filecounter}{0}%
\forcsvlist{\WriteOutputFileNameLabel}{#2}% Store the extensions to label 'names'
%
\noindent%
\textbf{\Large \textcolor{blue}{There are \number\value{pc@@totalfilecounter} file categories!}}
%
\setcounter{pc@@filecounter}{1}%
\setcounter{pc@@loopcounter}{\number\value{pc@@totalfilecounter}}
\addtocounter{pc@@loopcounter}{1}%
%
%
\begin{center}
\textbf{\textcolor{red}{Diagnostics}}
\end{center}
%
\whiledo{\number\value{pc@@filecounter} < \number\value{pc@@loopcounter}}{%
\noindent \nameref*{pc::outputfile::\number\value{pc@@filecounter}} \(\longrightarrow \) \jobname\nameref*{pc::outputfilename::\number\value{pc@@filecounter}}%
\stepcounter{pc@@filecounter}%
%% Creating the file handles file with error message `\protect`
\NewWrite{\nameref*{pc::outputfile::\number\value{pc@@filecounter}}}% %Creating file handle name `\anyname`
\newline%
} %
%%% Other code after
}%
\makeatother
\begin{document}
\RegisterOutputFiles{Problem,Hints,Solution,Explanation,Ideas,Concepts}{.prb,.hints,.sol,.explain,.idea,.concepts}%
\blindtext
\end{document}
笔记:
您必须删除循环中的%
before并运行两次才能看到最终的错误消息,第一个抱怨缺少引用。\NewWrite
pdflatex
代码尚未完成,也尚未完善,它是另一个包的一些概念研究的初始阶段。
答案1
您不能使用\nameref*
inside \csname...\endcsname
,因为它不是完全可扩展的。关联类别扩展最好使用不同的语法,其中两个部分彼此相邻,因此错误不太可能发生。
文件hupfer-handle.tex
\documentclass{article}
\usepackage{etoolbox}
\usepackage{morewrites}
\usepackage{xcolor}
\makeatletter
%% create a list of the open streams
\listadd{\cs@stream@list}{}% initialize
%% a unique command for allocating a stream and opening it if the
%% optional name argument is given
\newrobustcmd{\NewWrite}[2][]{%
\listadd{\ch@stream@list}{#2}%
\expandafter\newwrite\csname#2\endcsname
\ifblank{#1}{}{\immediate\openout\@nameuse{#2}=#1 }%
}
%% a helper macro for counting the number of items in the csv argument
\newcommand{\ch@count@streams}[1]{\advance\@tempcnta\@ne}
%% a helper macro for separating the two parts at the slash
\newcommand\ch@open@stream[1]{\ch@open@stream@aux#1\@nil}
\def\ch@open@stream@aux#1/#2\@nil{%
%% allocate a stream
\NewWrite[\jobname.#2]{#1}%
%% save the extension
\@namedef{ch@stream@@#1}{.#2}%
}
\newrobustcmd{\RegisterOutputFiles}[2]{%
%%% Other code before
%
\@tempcnta=\z@
\forcsvlist{\ch@count@streams}{#1}%
\forcsvlist{\ch@open@stream}{#1}%
\noindent
\textbf{\Large\textcolor{blue}{There are \number\@tempcnta\space file categories!}}%
\begin{center}
\textbf{\textcolor{red}{Diagnostics}}
\end{center}
\begingroup\parindent=\z@
\renewcommand{\do}[1]{Handle ``##1'' with extension \texttt{\@nameuse{ch@stream@@##1}}\par}
\dolistloop{\ch@stream@list}
\endgroup
%%% Other code after
}
\makeatother
\begin{document}
\RegisterOutputFiles{
Problem/prb,
Hints/hints,
Solution/sol,
Explanation/explain,
Ideas/idea,
Concepts/concepts
}
\end{document}
输出
文件列表
> ls hupfer-handle.*
hupfer-handle.aux hupfer-handle.hints hupfer-handle.mw hupfer-handle.sol
hupfer-handle.concepts hupfer-handle.idea hupfer-handle.pdf hupfer-handle.tex
hupfer-handle.explain hupfer-handle.log hupfer-handle.prb
答案2
这是另一个更直接的解决方案:
\documentclass{article}
\newcount\tmpnum
\def\RegisterOutputFiles#1#2{\tmpnum=0 \def\listsummary{}%
\registeroutputfilesA #1,,\relax #2,,\relax
}
\def\registeroutputfilesA #1,#2\relax #3,#4\relax{%
\if^#1^The number of categories: \the\tmpnum{\tt\listsummary}\else
\if^#3^\errmessage{?? less suffixes than categories.}\skiploop \fi
\advance\tmpnum by1
\csname newwrite\expandafter \endcsname \csname#1\endcsname
\immediate \expandafter\openout \csname#1\endcsname =\jobname#3
\edef\listsummary{\listsummary\endgraf
The \jobname#3 is opened as \expandafter\string\csname#1\endcsname}%
\registeroutputfilesA #2\relax #4\relax
\fi\relax
}
\def\skiploop #1\fi\relax{\fi\fi}
\begin{document}
\RegisterOutputFiles {Problem,Hints,Solution,Explanation,Ideas,Concepts}
{.prb,.hints,.sol,.explain,.idea,.concepts}
\end{document}
我在这里添加它是为了表明纯 TeX 的使用通常可以更加紧凑。