我想定义一个使用逐字环境的可选参数的新环境。我的代码如下:
\documentclass{article}
\usepackage{verbatim}
\begin{document}
\newenvironment{smurf}[1][]{
\verbatim
}{
\endverbatim
}
This is okay:
\begin{smurf}
x x x x x x
\end{smurf}
bla bla bla
This is okay, too:
\begin{smurf}[2]
x x x x x x
\end{smurf}
bla bla bla
This causes a strange error:
\begin{smurf}{2}
x x x x x x
\end{smurf}
bla bla bla
\end{document}
第三个例子导致了一个奇怪的错误。TeX 说:
Runaway argument?
{2}^^Mx x x x x x^^M\end{smurf}^^Mbla bla bla^^M^^M\end{document}^^M^^M
! File ended while scanning use of \verbatim@start.
我不明白为什么这是个问题。我该如何修复它?
答案1
您的smurf
环境(不改变类别代码制度)会寻找可选参数/查找是否存在,然后在“获取”可选参数(如果存在)后调用。[12
\verbatim
\verbatim
依次切换到 verbatim-category-code-régime 并依赖于在 verbatim-category-code-régime 下获取/被标记化的以下标记。
{
但是,在第三个例子中,的开头花括号{2}
并未根据 verbatim-category-code-régime 进行标记,因为在查找可选参数时,在\verbatim
被调用之前,它已经在正常/未改变的 category-code-régime 下进行了标记。
因此,在执行时,\verbatim
您已经有一个{
类别代码 1(开始组)的字符标记,但由于\verbatim
切换到逐字类别代码制度,随后的闭合花括号不会被标记为类别代码 2(结束组)字符标记,但会被标记为类别代码 12(其他)字符标记。因此,当\verbatim@start
收集其参数时,它会找到{
类别代码 1(开始组)的字符标记,但找不到}
类别代码 2(结束组)的匹配字符标记。这会导致错误Runaway argument?
。
由于正常类别代码制度下的类别代码[
与逐字类别代码制度下的相同,因此您可以实现一种机制,在切换到逐字类别代码制度(通过\let\do\@makeother\dospecials\@vobeyspaces\obeylines
)后,通过\kernel@ifnextchar
“查找”是否存在[
指示可选参数的存在。
\begin{smurf}
请注意,使用此方法时,您不能再通过使用换行符和空格的组合 来分离可选参数。
即,
使用
\begin{smurf}[optional]
该短语[optional]
不被视为逐字列表的一部分,而是被视为可选参数。
和
\begin{smurf} [optional]
该短语⟨space⟩[optional]
不被视为可选参数,而是被视为逐字列表的一部分。
和
\begin{smurf}
[optional]
该短语[optional]
不被视为可选参数,而是被视为逐字列表的一部分。
\documentclass{article}
\usepackage{verbatim}
\newcommand\FetchoptionalArgAndCallVerbatim[1][]{%
The optional argument---in parentheses---is: (#1)%
\verbatim
}%
\makeatletter
\newenvironment{smurf}{%
\begingroup
\let\do\@makeother
\dospecials
\@vobeyspaces
\obeylines
\kernel@ifnextchar[%
{\endgroup\FetchoptionalArgAndCallVerbatim}%
{\endgroup\FetchoptionalArgAndCallVerbatim[]}%
}{%
\endverbatim
}
\makeatother
\begin{document}
This is okay:
\begin{smurf}
x x x x x x
\end{smurf}
bla bla bla
This is okay, too:
\begin{smurf}[2]
x x x x x x
\end{smurf}
bla bla bla
This is okay, also:
\begin{smurf}[{\LaTeX[]}]
x x x x x x
\end{smurf}
bla bla bla
This no longer causes a strange error:
\begin{smurf}{2}
x x x x x x
\end{smurf}
bla bla bla
\end{document}
以下示例允许您\begin{smurf}
使用空格将可选参数与分隔开。
但是,未实现通过换行符进行分隔,因为这将消除逐字列表的第一行以打开的方括号开头的可能性[
/这将消除逐字列表的第一行以嵌套在方括号中的内容开头的可能性。[⟨something⟩]
即,
使用
\begin{smurf}[optional]
该短语[optional]
不被视为逐字列表的一部分,而是被视为可选参数。
和
\begin{smurf} [optional]
该短语⟨space⟩[optional]
不被视为逐字列表的一部分,而是[optional]
被视为可选参数。
和
\begin{smurf}
[optional]
该短语[optional]
不被视为可选参数,而是被视为逐字列表的一部分。
和
\begin{smurf}⟨space⟩
[optional]
该短语[optional]
不被视为可选参数,而是被视为逐字列表的一部分。
和
\begin{smurf}
⟨space⟩[optional]
该短语⟨space⟩[optional]
不被视为可选参数,而是被视为逐字列表的一部分。
\documentclass{article}
\usepackage{verbatim}
\newcommand\FetchoptionalArgAndCallVerbatim[1][]{%
The optional argument---in parentheses---is: (#1)%
\verbatim
}%
\makeatletter
\newenvironment{smurf}{%
\begingroup
\let\do\@makeother
\dospecials
\@vobeyspaces
\obeylines
\lookaheadloop{}%
}{%
\endverbatim
}
\begingroup
% As catcode of space will be changed, don't indent the following lines:
\@vobeyspaces%
\obeylines%
\@firstofone{% brace-level 1
\endgroup%
\newcommand\lookaheadloop[1]{% brace-level 2
\kernel@ifnextchar{ }{\gatherspace{#1}}{% brace-level 3
\kernel@ifnextchar[%
{\endgroup\FetchoptionalArgAndCallVerbatim}%
{\endgroup\FetchoptionalArgAndCallVerbatim[]#1}%
}% brace-level 3
}% brace-level 2
\@ifdefinable\gatherspace{\long\def\gatherspace#1 {\lookaheadloop{#1 }}}%
}% brace-level 1
% Now the catcode of space isn't changed any more.
\makeatother
\begin{document}
Example 1:
\begin{smurf}
x x x x x x
\end{smurf}
End of example 1.
Example 2:
\begin{smurf}[2]
x x x x x x
\end{smurf}
End of example 2.
Example 3:
\begin{smurf} [{\LaTeX[]}]
x x x x x x
\end{smurf}
End of example 3.
Example 4:
\begin{smurf}[{\LaTeX[]}]
x x x x x x
\end{smurf}
End of example 4.
Example 5:
\begin{smurf}
[{\LaTeX[]}]
x x x x x x
\end{smurf}
End of example 5.
Example 6:
\begin{smurf}
[{\LaTeX[]}]
x x x x x x
\end{smurf}
End of example 6.
Example 7:
\begin{smurf}
[{\LaTeX[]}]
x x x x x x
\end{smurf}
End of example 7.
Example 8:
\begin{smurf}{2}
x x x x x x
\end{smurf}
End of example 8.
Example 9:
\begin{smurf} {2}
x x x x x x
\end{smurf}
End of example 9.
Example 10:
\begin{smurf}
{2}
x x x x x x
\end{smurf}
End of example 10.
\end{document}
答案2
您正在强制向前查看是否存在可选参数。
后
\begin{smurf}{2}
没有,[
所以没有可选参数,但在查看时{
已经被看到并标记为一个正常的组开始{
。然后逐字内容被读取并且2}
逐字读取,所以永远不会有任何与之匹配的东西{
。
最简单的做法是使参数非可选,否则环境的第一个标记将永远不会被逐字读取。
不过你也许可以设置{
之前的 catcode:
\documentclass{article}
\usepackage{verbatim}
\begin{document}
\newenvironment{smurf}{% you need this % anyway
\catcode`\{=12 %
\smurfx
}{%
\endsmurfx
}
\newenvironment{smurfx}[1][]{% you need this % anyway
\verbatim
}{
\endverbatim
}
This is okay:
\begin{smurf}
x x x x x x
\end{smurf}
bla bla bla
This is okay, too:
\begin{smurf}[2]
x x x x x x
\end{smurf}
bla bla bla
This causes a strange error:
\begin{smurf}{2}
x x x x x x
\end{smurf}
bla bla bla
\end{document}