
2 人の査読者が私の論文にいくつかのコメントを寄せてくれたので、私は返答の手紙を書いています。私は次のように新しいコマンドを定義しました。
\newcommand{\response}[3]{Comment by Reviewer #1 \\ Comment: #2 \\ Response: #3}
論文に載っている順番に回答を書くつもりです。ただし、次のような別の文書も必要です。
レビュー担当者のコメント 1
コメント: これはコメントです。
回答: これが回答です。
...
レビュー担当者2のコメント
コメント: これはコメントです。
回答: これが回答です。
...
コマンドの最初の変数に従ってコマンドを並べ替えるにはどうすればよいでしょうか?
まだ文書の執筆を開始していないため、代替の解決策も歓迎します。
答え1
ここでのアプローチは
- 可能な査読者の名前は「John Doe」と「John Smith」であり
、応答と回答のエントリは外部ファイル\jobname.rvall
と\jobname.rvdoe
/に保存されます\jobname.rvsmith
。 (コメントとレスポンス)の 2 番目と 3 番目の引数は、
\response
verbatim-category-code-regime で読み取られます。これらの引数を中括弧でネストする代わりに、必要に応じて、-command
のように verbatim-delimiters を使用することもできます。\verb
本文内では、これらの引数は eTeX に渡されます
\scantokens
。.aux
これらの引数は、 -file およびファイル\jobname.rvall
と\jobname.rvdoe
それぞれの にもそのままコピー/書き込まれます\jobname.rvsmith
。
\jobname.rvall
および
\jobname.rvdoe
/ のファイルを を介して\jobname.rvsmith
他の TeX ドキュメントにインポートできます\input
。
必要なのは、これらの他の TeX ドキュメント内でマクロ\responselinewithreviewer
/\responselinewithoutreviewer
が 3 つの引数を処理するように定義されていることを確認することだけです。以下を
使用して、\UDcollectverbarg
verbatim-category-code-régime で -syntax を指定して 2 番目と 3 番目の引数を読み取るように定義すると\verb
、 や不均衡な中括弧なども含めることができます\verb
。
要点は次のとおりです。
これは、LaTeX 2e カーネルの/メカニズムの再実装のようなものです。(このメカニズムは、 / 、、などの基盤にもなっています。)@starttoc{⟨tocfile⟩}
\addtocontents{⟨tocfile⟩}{...}
\tableofcontents
\addcontentsline
\listoffigures
\listoftables
再実装では、verbatim-category-code-régime に基づいて引数を読み取り、処理します。
\listofallresponses
すべてのコメントと応答を配信します。
\dummylistofallresponses
.rvall
ドキュメントに内容を配信せずにファイルが書き込まれます。
\listofreviewersresponses{⟨reviewer⟩}
すべてのコメントと返答を配信します⟨レビュアー⟩。
\dummylistofreviewersresponses{⟨reviewer⟩}
原因は.rv⟨reviewer⟩
- ファイルの内容をドキュメントに配信せずに書き込む。
ファイルtest.tex
:
% Due to usage of \detokenize and \scantokens compiling this file
% requires LaTeX with eTeX-extensions.
\makeatletter
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
%%=============================================================================
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\@firstofone{\expandafter} %
\@secondoftwo}{\@firstofone{\expandafter} \@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \UD@ExtractKthArg{<integer K>}{<list of undelimited args>}
%%
%% In case there is no K-th argument in <list of indelimited args> :
%% Does not deliver any token.
%% In case there is a K-th argument in <list of indelimited args> :
%% Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%% \UD@ExtractKthArg{0}{ABCDE} yields: <nothing>
%%
%% \UD@ExtractKthArg{3}{ABCDE} yields: C
%%
%% \UD@ExtractKthArg{3}{AB{CD}E} yields: CD
%%
%% \UD@ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
%%
%% \UD@ExtractKthArg{6}{{001}{002}{003}} yields: <nothing>
%%
%%=============================================================================
\newcommand\UD@ExtractKthArg[1]{%
\romannumeral0%
% #1: <integer number K>
\expandafter\UD@ExtractKthArgCheck
\expandafter{\romannumeral\number\number#1 000}%
}%
\newcommand\UD@ExtractKthArgCheck[2]{%
\UD@CheckWhetherNull{#1}{ }{%
\expandafter\UD@ExtractKthArgLoop\expandafter{\@firstoftwo{}#1}{#2}%
}%
}%
\newcommand\UD@ExtractKthArgLoop[2]{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo#2{}.}{ }{%
\UD@CheckWhetherNull{#1}{%
\UD@ExtractFirstArgLoop{#2\UD@SelDOm}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\@firstoftwo{}#2}%
{\expandafter\UD@ExtractKthArgLoop\expandafter{\@firstoftwo{}#1}}%
}%
}%
}%
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
{\@firstoftwo\expandafter{} \@secondoftwo{}#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% Check whether argument contains no exclamation mark which is not nested in
%% braces:
%%.............................................................................
%% \UD@CheckWhetherNoExclam{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% contains no exclamation mark>}%
%% {<Tokens to be delivered in case that argument
%% contains exclamation mark>}%
%%=============================================================================
\newcommand\UD@GobbleToExclam{}\long\def\UD@GobbleToExclam#1!{}%
\newcommand\UD@CheckWhetherNoExclam[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToExclam#1!}%
}%
%%=============================================================================
%% Act depending on whether argument is "John Doe" or "John Smith":
%% \reviewerfork{<Argument>}{%
%% {<tokens in case <Argument> is John Doe>}%
%% {<tokens in case <Argument> is John Smith>}%
%% {<tokens in case <Argument> is something else>}%
%% }
%%=============================================================================
\newcommand\reviewerfork[1]{%
\romannumeral0%
\UD@CheckWhetherNoExclam{#1}{%
\@reviewerfork
!#1!John Smith!{\@firstoftwo{\expandafter\expandafter\expandafter}{} \UD@ExtractKthArg{1}}%
!John Doe!#1!{\@firstoftwo{\expandafter\expandafter\expandafter}{} \UD@ExtractKthArg{2}}%
!John Doe!John Smith!{\@firstoftwo{\expandafter\expandafter\expandafter}{} \UD@ExtractKthArg{3}}%
!!!!%
}{%
\@firstoftwo{\expandafter\expandafter\expandafter}{} \UD@ExtractKthArg{3}%
}%
}%
\newcommand\@reviewerfork{}%
\long\def\@reviewerfork#1!John Doe!John Smith!#2#3!!!!{#2}%
%%=============================================================================
%% Act depending on whether is known/unknown:
%% \CheckWhetherReviewerknown{<Argument>}
%% {<tokens in case <Argument> is a known reviewer>}%
%% {<tokens in case <Argument> is not a known reviewer>}%
%%=============================================================================
\newcommand\CheckWhetherReviewerknown[1]{%
\romannumeral0%
\reviewerfork{#1}{%
{\@firstofone{\expandafter} \@firstoftwo}%
{\@firstofone{\expandafter} \@firstoftwo}%
{\@firstofone{\expandafter} \@secondoftwo}%
}%
}%
%%=============================================================================
%% Error-message in case the reviewer is unknown:
%% \unknownreviewererror{<reviewer>}%
%% {<name of macro that called \unknownreviewererror>}
%%=============================================================================
\newcommand\unknownreviewererror[2]{%
\GenericError{%
\space\space\space\@spaces\@spaces\@spaces
}{%
\@backslashchar#2-error\on@line: Reviewer `\detokenize{#1}' unknown%
}{%
See the comments of this file for explanation.%
}{%
Known reviewers in this demo are `John Doe' and `John Smith'.%
\MessageBreak(The reviewer-argument is case sensitive.)%
}%
}%
%%======================Code for \UDcollectverbarg=============================
%% \UDcollectverbarg{^^M-replacement}{<mandatory 1>}{<mandatory 2>}|<verbatim arg>|
%%
%% reads <verbatim arg> under verbatim-catcode-regime and delivers:
%%
%% <mandatory 1>{<mandatory 2>{<verbatim arg>}{|<verbatim arg>|}}
%%
%% Instead of verbatim-delimiter | the <verbatim arg> can be nested in braces.
%% You cannot use percent or spaces or horizontal tab as verbatim-delimiter.
%%
%% You can use <mandatory 1> for nesting calls to \UDcollectverbarg.
%% <mandatory 2> gets the <verbatim arg> twice: Once without verbatim-delimiters/braces,
%% once surrounded by verbatim-delimiters/braces.
%% Reason: When you feed it to \scantokens you don't need the verbatim-delimiters.
%% When you use it for writing to temporary files and reading back,
%% you need them.
%%=============================================================================
\begingroup
\catcode`\^^M=12 %
\@firstofone{%
\endgroup%
\newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
\@ifdefinable\@UDEndlreplace{%
\long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
\UD@CheckWhetherNull{#3}%
{ #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
}%
}%
}%
\newcommand\UDcollectverbarg[3]{%
\begingroup
\let\do\@makeother % <- this and the next line switch to
\dospecials % verbatim-category-code-régime.
\catcode`\{=1 % <- give opening curly brace the usual catcode so a
% curly-brace-balanced argument can be gathered in
% case of the first thing of the verbatimized-argument
% being a curly opening brace.
\catcode`\ =10 % <- give space and horizontal tab the usual catcode so \UD@collectverbarg
\catcode`\^^I=10 % cannot catch a space or a horizontal tab as its 4th undelimited argument.
% (Its 4th undelimited argument denotes the verbatim-
% syntax-delimiter in case of not gathering a
% curly-brace-nested argument.)
\catcode`\%=14 % <- make percent comment.
\kernel@ifnextchar\bgroup
{% seems a curly-brace-nested argument is to be caught:
\catcode`\}=2 % <- give closing curly brace the usual catcode also.
\UD@collectverbarg{#1}{#2}{#3}{}%
}{% seems an argument with verbatim-syntax-delimiter is to be caught:
\do\{% <- give opening curly brace the verbatim-catcode again.
\UD@collectverbarg{#1}{#2}{#3}%
}%
}%
\newcommand\UD@collectverbarg[4]{%
\do\ % <- Now that \UD@collectverbarg has the delimiter or
\do\^^I% emptiness in its 4th arg, give space and horizontal tab
% the verbatim-catcode again.
\do\^^M% <- Give the carriage-return-character the verbatim-catcode.
\do\%% <- Give the percent-character the verbatim-catcode.
\long\def\@tempb##1#4{%
\def\@tempb{##1}%
\UD@CheckWhetherNull{#4}{%
\def\@tempc{{##1}}%
}{%
\def\@tempc{#4##1#4}%
}%
\@onelevel@sanitize\@tempb % <- Turn characters into their "12/other"-pendants.
% This may be important with things like the
% inputenc-package which may make characters
% active/which give them catcode 13(active).
\expandafter\UDEndlreplace\expandafter{\@tempb}{#1}{\def\@tempb}% <- this starts
% the loop for replacing endline-characters.
\@onelevel@sanitize\@tempc
\expandafter\UDEndlreplace\expandafter{\@tempc}{#1}{\def\@tempc}%
\expandafter\expandafter\expandafter\UD@@collectverbarg% <- this "spits out the result.
\expandafter\expandafter\expandafter{%
\expandafter\@tempb\expandafter}%
\expandafter{\@tempc}{#2}{#3}%
}%
\@tempb
}%
\newcommand\UD@@collectverbarg[4]{%
\endgroup
#3{#4{#1}{#2}}%
}%
%%================= End of code for \UDcollectverbarg =========================
%%=============================================================================
%% \response{<reviewer>}{<comment>}{<response>}
%% adds entries to toc-like-files \jobname.rvdoe or \jobname.rvsmith
%% and \jobname.rvall
%%=============================================================================
\@ifdefinable\response{%
\outer\long\def\response#1{%
\UDcollectverbarg{^^J}{%
\UDcollectverbarg{^^J}{\@firstofone}%
}{\innerresponse{#1}}%
}%
}%
\begingroup
% Now ^^A is used instead of %:
\catcode`\^^A=\the\catcode`\%\relax
\catcode`\%=12\relax
\@firstofone{^^A
\endgroup
\newcommand\innerresponse[5]{^^A
^^A #1 = <reviewer>
^^A #2 = <verbatimized comment without surrounding verbatim-delimiters>
^^A #3 = <verbatimized comment with surrounding verbatim-delimiters>
^^A #4 = <verbatimized response without surrounding verbatim-delimiters>
^^A #5 = <verbatimized response with surrounding verbatim-delimiters>
\CheckWhetherReviewerknown{#1}{^^A
\par\bigskip\noindent Comment by reviewer #1\\Comment: \scantokens{#2%}\\Response: \scantokens{#4%}^^A
\responseentries{#1}{#3}{#5}^^A
}{^^A
\unknownreviewererror{#1}{response}^^A
}^^A
}^^A
\newcommand\@innerresponsewritefile[1]{^^A
\renewcommand\@innerresponsewritefile[6]{^^A
^^A #1 = space token
^^A ##1 = rv<reviewer> (filename-extension)
^^A ##2 = <reviewer>
^^A ##3 = <verbatimized comment without surrounding verbatim-delimiters>
^^A ##4 = <verbatimized comment with surrounding verbatim-delimiters>
^^A ##5 = <verbatimized response without surrounding verbatim-delimiters>
^^A ##6 = <verbatimized response with surrounding verbatim-delimiters>
\expandafter\UD@PassFirstToSecond\expandafter{^^A
\string\responselinewithreviewer^^J#1#1{##2}%^^J#1#1##4%^^J#1#1##6%^^A
}^^A
{\@writefile{rvall}}^^A
\expandafter\UD@PassFirstToSecond\expandafter{^^A
\string\responselinewithoutreviewer^^J#1#1{##2}%^^J#1#1##4%^^J#1#1##6%^^A
}^^A
{\@writefile{##1}}^^A
}^^A
}^^A
\@innerresponsewritefile{ }^^A
\newcommand\innerresponselinewithreviewer[5]{^^A
^^A #1 = <reviewer>
^^A #2 = <verbatimized comment without surrounding verbatim-delimiters>
^^A #3 = <verbatimized comment with surrounding verbatim-delimiters>
^^A #4 = <verbatimized response without surrounding verbatim-delimiters>
^^A #5 = <verbatimized response with surrounding verbatim-delimiters>
\par\bigskip\noindent Comment by reviewer #1\\Comment: \scantokens{#2%}\\Response: \scantokens{#4%}^^A
}^^A
\newcommand\innerresponselinewithoutreviewer[5]{^^A
^^A #1 = <reviewer>
^^A #2 = <verbatimized comment without surrounding verbatim-delimiters>
^^A #3 = <verbatimized comment with surrounding verbatim-delimiters>
^^A #4 = <verbatimized response without surrounding verbatim-delimiters>
^^A #5 = <verbatimized response with surrounding verbatim-delimiters>
\par\bigskip\noindent Comment: \scantokens{#2%}\\Response: \scantokens{#4%}^^A
}^^A
}% <- \@firstofone with changed catcodes done.
\newcommand\responseentries[3]{%
% #1 = <reviewer>
% #2 = <verbatimized comment with surrounding verbatim-delimiters>
% #3 = <verbatimized response with surrounding verbatim-delimiters>
\protected@write\@mainaux{}{%
\string\@responsewritefile{\reviewerfork{#1}{{rvdoe}{rvsmith}{}}}\@percentchar^^J\space\space
{#1}\@percentchar^^J\space\space
#2\@percentchar^^J\space\space
#3\@percentchar
}%
}%
\newcommand\@responsewritefile[2]{%
% #1 = rv<reviewer> (filename-extension)
% #2 = <reviewer>
\UDcollectverbarg{^^J}{%
\UDcollectverbarg{^^J}{\@firstofone}%
}{\@innerresponsewritefile{#1}{#2}}%
}%
\newcommand\responselinewithreviewer[1]{%
% #1 = <reviewer>
\UDcollectverbarg{^^J}{%
\UDcollectverbarg{^^J}{\@firstofone}%
}{\innerresponselinewithreviewer{#1}}%
}%
\newcommand\responselinewithoutreviewer[1]{%
% #1 = <reviewer>
\UDcollectverbarg{^^J}{%
\UDcollectverbarg{^^J}{\@firstofone}%
}{\innerresponselinewithoutreviewer{#1}}%
}%
%%=============================================================================
%% \listofallresponses
%% delivers all comments and responses.
%%
%% \dummylistofallresponses
%% causes the .rvall-file to be written without delivering things into
%% the document.
%%=============================================================================
\newcommand\listofallresponses{%
\par\noindent ALL COMMENTS\par
\@starttoc{rvall}%
}%
\newcommand\dummylistofallresponses{%
\@dummystarttoc{rvall}%
}%
%%=============================================================================
%% \listofreviewersresponses{<reviewer>}%
%% delivers all comments and responses that belong tp <reviewer>.
%%
%% \dummylistofreviewersresponses{<reviewer>}%
%% causes the .rv<reviewer>-file to be written without delivering its
%% content into the document.
%%=============================================================================
\newcommand\listofreviewersresponses[1]{%
\reviewerfork{#1}{%
{\par\noindent COMMENTS BY REVIEWER JOHN DOE\par\@starttoc{rvdoe}}%
{\par\noindent COMMENTS BY REVIEWER JOHN SMITH\par\@starttoc{rvsmith}}%
{\unknownreviewererror{#1}{listofreviewersresponses}}%
}%
}%
\newcommand\dummylistofreviewersresponses[1]{%
\reviewerfork{#1}{%
{\@dummystarttoc{rvdoe}}%
{\@dummystarttoc{rvsmith}}%
{\unknownreviewererror{#1}{dummylistofreviewersresponses}}%
}%
}%
\newcommand\@dummystarttoc[1]{%
\begingroup
\makeatletter
\if@filesw
\expandafter\newwrite\csname tf@#1\endcsname
\immediate\openout\csname tf@#1\endcsname\jobname.#1\relax
\fi
\@nobreakfalse
\endgroup
}%
\makeatother
\documentclass{article}
\usepackage{verbatim}% <- used only for \verbatiminput
\begin{document}
\enlargethispage{3cm}%
\vspace*{-3cm}%
\par\bigskip\noindent\textbf{\jobname.rvall looks like this:}
\verbatiminput{\jobname.rvall}%
\par\bigskip\noindent\textbf{\jobname.rvdoe looks like this:}
\verbatiminput{\jobname.rvdoe}%
\par\bigskip\noindent\textbf{\jobname.rvsmith looks like this:}
\verbatiminput{\jobname.rvsmith}%
\newpage
\InputIfFileExists{\jobname.rvall}{\par\bigskip\noindent\textbf{Inputting \jobname.rvall yields:}}{}
\InputIfFileExists{\jobname.rvdoe}{\par\bigskip\noindent\textbf{Inputting \jobname.rvdoe yields:}}{}%
\InputIfFileExists{\jobname.rvsmith}{\par\bigskip\noindent\textbf{Inputting \jobname.rvsmith yields:}}{}%
\newpage
% now let's cause the .rvall-file and the .rvdoe-file and the .rvsmith-file
% to be created_
%
% This will also import the files:
%
%\listofreviewersresponses{John Smith}%
%\bigskip
%\listofallresponses
%\bigskip
%\listofreviewersresponses{John Doe}%
%
% This will cause creation of these files only.
%
\dummylistofallresponses
\dummylistofreviewersresponses{John Smith}%
\dummylistofreviewersresponses{John Doe}%
\par\bigskip\noindent\textbf{The text of the main document is:}
\bigskip\noindent Some text.
\response{John Doe}{John Doe's first comment.}{Response to John Doe's first comment.}
\response{John Smith}%
{John Smith's first comment.}%
{Response to John Smith's first comment.}
\response{John Doe}{John Doe's second comment. It has verbatim
material: \verb|\TeX is funny|.
}{Response to John Doe's second comment.}
\response{John Smith}%
{John Smith's second comment.}%
|Response to John Smith's second comment.
It has verbatim material
with unbalanced braces:
\verb+\TeX}}} is funny!+|
\end{document}