回复:缺少可选参数导致环境的第一项被当作可选参数执行

回复:缺少可选参数导致环境的第一项被当作可选参数执行
\documentclass{article}
\usepackage{verbatim}
%\usepackage{fancyvrb}
\usepackage{xcolor}
\usepackage{xkeyval}

%RE: LACK OF OPTIONAL ARGUMENT MAKES 1ST ITEM OF ENVIRONMENT GET EXECUTED AS IF IT WERE OPTIONAL ARGUMENT

\makeatletter
\newwrite\verbatim@out%

\def\verbatimout#1{
 \begingroup%group to localise cat code reassignment?
  \immediate\openout\verbatim@out#1%
  \let\do\@makeother\dospecials%
  \catcode`\^^M\active%
  \def\verbatim@processline{%
%\the\verbatim@line%
%\typeout{VERBATIM: \the\verbatim@line}%
   \immediate\write\verbatim@out{\the\verbatim@line}}%
  \verbatim@start%
}

%\def\setverbatimout#1{
% \begingroup
%  \immediate\openout\verbatim@out#1%
%  \def\verbatim@processline{%
%   \typeout{VERBATIM: \the\verbatim@line}%
%   \immediate\write\verbatim@out{\the\verbatim@line}}%
%}

\def\endverbatimout{%
%\endverbatim
 \immediate\closeout\verbatim@out%\@esphack%
 \endgroup
}

\def\mykeys@color{black}
\define@key{mykeys}{color}{\def\mykeys@color{#1}}

\newenvironment{verboptfail}[1][]{\verbatim}{\endverbatim}

\newenvironment{verbopt}{\verbatim\verboptarg}{\endverbatim}
\newcommand\verboptarg[1][]{\setkeys{mykeys}{#1}\color{\mykeys@color}\typeout{:::#1:::}}

%NOTE: replacing \verbatim with \verbatimout{filename} and \endverbatim with \endverbatimout does not work, as \verboptarg is simply not picked up.  Why? catcodes?

\gdef\opts{}

%\newenvironment{verbout}{\setverbatimout{1.temp}\verbatim\verboutarg}{\endverbatimout\setkeys{mykeys}{\opts}\color{\mykeys@color}\verbatiminput{1.temp}}
\newenvironment{verbout}{\verbatimout{1.temp}\verboutarg}{\endverbatimout\setkeys{mykeys}{\opts}\color{\mykeys@color}\verbatiminput{1.temp}}

%\newcommand\verboutarg[1][]{{\nfss@catcodes\scantokens{\gdef\opts{#1}\typeout{***\opts***}}}}%typeout never gets executed!
\newcommand\verboutarg[1][]{\gdef\opts{#1}\typeout{***\opts***}}%typeout never gets executed!

\makeatother
\begin{document}
standard verbatim environment with a problem - well that's where we started!

\begin{verbatim}\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbatim}

%the following fails to compile when we remove REMOVEME!
\begin{verboptfail}REMOVEME\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboptfail}

our verbopt environment works fine

\begin{verbopt}
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}

\begin{verbopt}\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}

\begin{verbopt}[color=blue]\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| with arg
\end{verbopt}

\begin{verbopt}[]
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
  with EMPTY optional arg
\end{verbopt}

************ we can't get our verbout environment to work - we find `[color=blue]' etc in the output file, and keyvalues have not been set! *************

\begin{verbout}
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}

\begin{verbout}\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}

\begin{verbout}[color=blue]
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}

\begin{verbout}[]
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
  with EMPTY optional arg
\end{verbout}
\end{document}

标准逐字环境存在问题——好吧,这就是我们开始的地方!

\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
REMOVEME\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|

我们的 verbopt 环境运行良好

\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\| without arg
\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\| without arg
\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\| with arg
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|

如果可选参数为空 ****,我们无法使 verbout 环境工作 - 我们在输出文件中发现 '[color=blue]' 等,并且键值尚未设置!************ ************* ************** *************** *************** *************** *************** *************** ***************

\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
[color=blue]
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
[]
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|

带有空的可选参数

答案1

这应该会让你更进一步。

首先,你的verbopt环境确实不能正常工作。如果行中没有文本,它会产生一个空行\begin{verbopt}

环境verbiopt通过使用环境的可选参数来定义它来解决这个问题。但是,如果在同一行中没有可选参数文本,\begin{verbiopt}则会产生错误,如果它以 TeX 命令开头,\more在示例中,该命令也会被吞掉。如果文本不是以命令开头,或者该行中没有文本,则没有问题。

对于verbout环境,将参数提供给环境也更有意义。在您的示例中,您可以在环境的开头设置键(注释掉的版本)。但这可能并不总是可行的。因此,使用的版本使用环境末尾的参数。

这里需要注意的是,这\setkeys{mykeys}{\verbopts}将不起作用,因为\verbopts扩展得太晚了。\setkeys将被color=blue视为键(没有值),然后抱怨未知键。为了解决这个问题,\setmykeys使用了宏。它使用已经扩展的来调用\verbopts,使用\expandafter\setmykeys\expandafter{\verbopts}

verbout环境在文本在同一行时也存在问题\begin{verbout}。但这里只是吞下了一个命令,没有错误。

还有环境verboutfile,它为文件名添加了一个附加强制参数,因此文本可以存储在不同的文件中。此环境与 在同一行中没有文本问题\begin{verboutfile}

代码(会产生错误,见上文):

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{verbatim}
%\usepackage{fancyvrb}
\usepackage{xcolor}
\usepackage{xkeyval}

%RE: LACK OF OPTIONAL ARGUMENT MAKES 1ST ITEM OF ENVIRONMENT GET EXECUTED AS IF IT WERE OPTIONAL ARGUMENT

\makeatletter
\newwrite\verbatim@out%

\def\verbatimout#1{
 \begingroup%group to localise cat code reassignment?
  \immediate\openout\verbatim@out#1%
  \let\do\@makeother\dospecials%
  \catcode`\^^M\active%
  \def\verbatim@processline{%
   \immediate\write\verbatim@out{\the\verbatim@line}}%
  \verbatim@start%
}

\def\endverbatimout{%
 \immediate\closeout\verbatim@out
 \endgroup
}

\def\mykeys@color{black}
\define@key{mykeys}{color}{\def\mykeys@color{#1}}

\newenvironment{verboptfail}[1][]{\verbatim}{\endverbatim}

\newenvironment{verbopt}{\verbatim\verboptarg}{\endverbatim}
\newcommand\verboptarg[1][]{\setkeys{mykeys}{#1}\color{\mykeys@color}\typeout{:::#1:::}}

\newenvironment{verbiopt}[1][]{%
    \setkeys{mykeys}{#1}\typeout{:::#1:::}%
    \color{\mykeys@color}%
    \verbatim
}{%
    \endverbatim
}

% with key set at start of environment, would work here
%\newenvironment{verbout}[1][]{%
%    \setkeys{mykeys}{#1}\typeout{***#1***}\verbatimout{1.temp}%
%}{%
%    \endverbatimout\color{\mykeys@color}\verbatiminput{1.temp}%
%}

% optional argument used at end of environment
\newenvironment{verbout}[1][]{%
    \verboutarg{#1}\verbatimout{1.temp}%
}{%
    \endverbatimout
    \expandafter\setmykeys\expandafter{\verbopts}%
    \color{\mykeys@color}\verbatiminput{1.temp}%
}
\newcommand\verboutarg[1]{\gdef\verbopts{#1}\typeout{***#1***}}
\newcommand\setmykeys[1]{\setkeys{mykeys}{#1}}

% file name as second mandatory argument, both used at end of environment
\newenvironment{verboutfile}[2][]{%
    \verboutfilearg{#1}{#2}\verbatimout{#2}%
}{%
    \endverbatimout
    \expandafter\setmykeys\expandafter{\verbopts}%
    \color{\mykeys@color}\verbatiminput{\verbfile}%
}
\newcommand\verboutfilearg[2]{%
    \gdef\verbopts{#1}\typeout{***#1***}%
    \gdef\verbfile{#2}\typeout{>>>#2<<<}%
}
%same as above
%\newcommand\setmykeys[1]{\setkeys{mykeys}{#1}}

\makeatother
\begin{document}
\noindent
using verbopt environment; issue: empty first line in (1) and (4) example

\noindent
XXXXXXXXXXXX
\begin{verbopt}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}
XXXXXXXXXXXX

\begin{verbopt}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}
XXXXXXXXXXXX

\begin{verbopt}[color=blue]\more\verb
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| with arg
\end{verbopt}
XXXXXXXXXXXX

\begin{verbopt}[]
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
  with EMPTY optional arg
\end{verbopt}
XXXXXXXXXXXX

\vfill
\noindent
using verbiopt environment; issue: \verb|\more| in (2) is expanded, therefore error

\noindent
XXXXXXXXXXXX
\begin{verbiopt}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbiopt}
XXXXXXXXXXXX

\begin{verbiopt}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbiopt}
XXXXXXXXXXXX

\begin{verbiopt}[color=blue]\more\verb
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| with arg
\end{verbiopt}
XXXXXXXXXXXX

\begin{verbiopt}[]
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
  with EMPTY optional arg
\end{verbiopt}
XXXXXXXXXXXX

\newpage
\noindent
using verbout environment, issue: swallows \verb|\more| in (2)

\noindent
XXXXXXXXXXXX
\begin{verbout}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
XXXXXXXXXXXX

\begin{verbout}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
XXXXXXXXXXXX

\begin{verbout}[color=blue]
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
XXXXXXXXXXXX

\begin{verbout}[]
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
  with EMPTY optional arg
\end{verbout}
XXXXXXXXXXXX

\vfill
\noindent
using verboutfile environment with file name as argument

\noindent
XXXXXXXXXXXX
\begin{verboutfile}{1.tmp}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboutfile}
XXXXXXXXXXXX

\begin{verboutfile}{2.tmp}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboutfile}
XXXXXXXXXXXX

\begin{verboutfile}[color=blue]{3.tmp}
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboutfile}
XXXXXXXXXXXX

\begin{verboutfile}[]{4.tmp}
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
  with EMPTY optional arg
\end{verboutfile}
XXXXXXXXXXXX
\end{document}

答案2

关于强制参数的使用。我的非最小(或真实)环境实际上是根据计数机制发明文件名的,所以我不想要强制参数。我们总是可以写一个空的强制参数,但如果我们忘记了,那么我们就会回到起点!当然,如果我们假设“可选”参数是强制的,那就没有问题了——我的意思是,如果我们总是写可选参数,即使它是空的[]。这样我们就不会忘记写[],那么我们可以在环境定义中测试它并报告错误消息。话虽如此,我正在考虑以下解决方案:

\documentclass{article}
\usepackage{verbatim,xcolor,nopageno}
\makeatletter
\newwrite\verbatim@out%
\def\verbatimout#1{\begingroup\immediate\openout\verbatim@out#1\let\do\
@makeother\dospecials\catcode ` \^^M\active\def\verbatim@processline{\
typeout{VERBATIM: \the\verbatim@line}\immediate\write\verbatim@out{\the\
verbatim@line}}\verbatim@start}
\def\endverbatimout{\immediate\closeout\verbatim@out\endgroup}
\newenvironment{myenv}{\@ifnextchar[{\@myarg}{\errmessage{some error
 message}\verbatimout{1.temp}}}{\endverbatimout\verbatiminput{1.temp}}
\def\@myarg[#1]{{\color{red}[#1]}\verbatimout{1.temp}}%delimited arg
\makeatother
\begin{document}\noindent
xxxxxxxxxxxxxxxxxxxx
\begin{myenv}\more\verb
\x\y\z␣!" $ %^&*() +
\end{myenv}
xxxxxxxxxxxxxxxxxxxx
\begin{myenv}[]\more\verb
\x\y\z␣!" $ %^&*() +
\end{myenv}
xxxxxxxxxxxxxxxxxxxx
\end{document}

这使

xxxxxxxxxxxxxxxxxxxx
\verb
\x\y\z !"$%^&*()_+
xxxxxxxxxxxxxxxxxxxx []
\more\verb
\x\y\z !"$%^&*()_+
xxxxxxxxxxxxxxxxxxxx

现在,它似乎表现得像 fan-cyvrb 包中的 (V)erbatim(O)out{} 宏。即使我们没有 [],甚至根本没有使用键值,fancyvrb 包也会给出乱码错误消息:“\beginmyenv[key-value] 和行尾之间有多余的输入”!

相关内容