以相同方式激活并使用字符来定义宏在逐字环境中的行为有所不同

以相同方式激活并使用字符来定义宏在逐字环境中的行为有所不同

下面的 MCE 表明Unicode 和 ASCII字符被激活并且以与定义宏完全相同的方式使用,当用 进行编译时lualatex,在逐字环境中的行为有所不同:&像魔法一样工作,但°会失败并出现以下错误:

! Argument of \FV@GetKeyValues has an extra }.
<inserted text> 
\par 
l.29 °Bar° in verbatim.

你知道为什么会出现这些不同的行为吗?

\documentclass{article}
\usepackage{fancyvrb}
\begin{document}

\catcode`\&=\active
\long\def &#1&{\textbf{#1}}

\catcode`\°=\active
\long\def °#1°{\textbf{#1}}

&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

°Bar° in text.
\begin{VerbatimOut}{example-2.tex}
°Bar° in verbatim.
\end{VerbatimOut}
\end{document}

编辑

事实上,不同的行为并不是来自 Unicode 字符和 ASCII 字符,因为对于!而不是也会出现同样的问题°

\documentclass{article}
\usepackage{fancyvrb}
\begin{document}

\catcode`\&=\active
\long\def &#1&{\textbf{#1}}

\catcode`\!=\active
\long\def !#1!{\textbf{#1}}

&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

!Bar! in text.
\begin{VerbatimOut}{example-2.tex}
!Bar! in verbatim.
\end{VerbatimOut}
\end{document}

汇编如下:

! Argument of \FV@GetKeyValues has an extra }.
<inserted text> 
\par 
l.29 !Bar! in verbatim.

编辑2

这是这个问题的背景。对于 LaTeX 教程,我显示了 LaTeX 代码片段及其结果。对于其中一些,我想在代码和结果中突出显示一些 LaTeX 命令。为此,我使用了类似以下内容(在我的实际文件中,LaTeX 命令以与结果相同的颜色背景突出显示,为此,我使用了扩展版本的但整个代码会挤满示例):

\documentclass{article}
\usepackage{lmodern}
\usepackage{xcolor}
\usepackage{listings}
\usepackage{fancyvrb}

\lstset{%
  basicstyle=\ttfamily,
  frame=single,
  framesep=2pt,
  aboveskip=1ex,
  moredelim=**[is][\color{red!50}]{°}{°},
}

\newenvironment{showexample}{%
  \VerbatimOut{example.tex}%
}{
  \endVerbatimOut%
  \lstinputlisting{example.tex}
  \input{example.tex}
}

\makeatletter
\g@addto@macro\dospecials{\do\°}
\g@addto@macro\@sanitize{\@makeother\°}
\makeatother

\catcode`\°=\active
\long\def °#1°{\colorbox{red!50}{#1}}

\begin{document}
\begin{showexample}
°\emph{Bar}°: ``Bar'' is emphazised.
\end{showexample}
\end{document}

在此处输入图片描述

答案1

每个verbatim环境(包括fancyvrb的后代)&在开始读取材料之前明确设置为类别代码 12。

fancyvrb包具有声明其他字符的类别代码的功能。

\documentclass{article}
\usepackage{fancyvrb}

\begin{document}

\catcode`\&=\active
\long\def&#1&{\textbf{#1}}

\catcode`\°=\active
\long\def °#1°{\textbf{#1}}

&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

°Bar° in text.
\begin{VerbatimOut}[codes={\catcode`°=12}]{example-2.tex}
°Bar° in verbatim.
\end{VerbatimOut}
\end{document}

这将是example-2.tex

°Bar° in verbatim.

您也可以“全局”设置它:

\documentclass{article}
\usepackage{fancyvrb}

\fvset{codes={\catcode`°=12}}

\begin{document}

\catcode`\&=\active
\long\def&#1&{\textbf{#1}}

\catcode`\°=\active
\long\def °#1°{\textbf{#1}}

&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

°Bar° in text.
\begin{VerbatimOut}{example-2.tex}
°Bar° in verbatim.
\end{VerbatimOut}
\end{document}

另一方面,verbatim对 不做特殊处理!,因为它通常是其他字符(类别代码 12),因此如果您将其设置为活动,它将在 内保持活动状态verbatim。因此您的第二个示例需要

codes={\catcode`!=12}

答案2

目前我使用的是 debian-linux 的 texlive。更新 debian-package luaotfload-tool 后,通过以下方式编译路拉泰克斯

\documentclass{article}

\usepackage{iftex}
\ifPDFTeX
  \usepackage[T1]{fontenc}
  \usepackage{textcomp}
  \usepackage[utf8]{inputenc}
\else
  \usepackage{fontspec}
\fi

\usepackage{verbatim, fancyvrb}

\makeatletter
\newcommand\exchange[2]{#2#1}
\newcommand\local@addto@macro[2]{%
  \expandafter\exchange\expandafter{\expandafter\toks@\expandafter{\the\toks@}}{%
    \toks@\expandafter{#1#2}\edef#1{\the\toks@}%
  }%
}%
\makeatother

\begin{document}

\begingroup

\makeatletter
% & is already in the specials-list
\local@addto@macro\dospecials{\do\°}
\local@addto@macro\dospecials{\do\!}
\makeatother

\catcode`\&=\active
\long\def &#1&{\textbf{#1}}

\catcode`\°=\active
\long\def °#1°{\textbf{#1}}

\catcode`\!=\active
\long\def !#1!{\textbf{#1}}

\message{%
  Here \string° and \string! are active, thus they need
  to be added to LaTeX's^^Jverb-mechanism's specials-list:%
}%
\show\dospecials

&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

°Bar° in text.
\begin{VerbatimOut}{example-2.tex}
°Bar° in verbatim.
\end{VerbatimOut}

!Baz! in text.
\begin{VerbatimOut}{example-3.tex}
!Baz! in verbatim.
\end{VerbatimOut}

\endgroup

\message{%
  Here \string° and \string! are not active any more, thus they don't
  need to be added to^^JLaTeX's verb-mechanism's specials-list any more:%
}%
\show\dospecials

\section{This is \texttt{example-1.tex}:}

\verbatiminput{example-1.tex}

\section{This is \texttt{example-2.tex}:}

\verbatiminput{example-2.tex}

\section{This is \texttt{example-3.tex}:}

\verbatiminput{example-3.tex}

\end{document}

得到我:

在此处输入图片描述

当然可以通过 fancyverb 的codes=-key 指定其他特殊字符,如下所示egreg 的回答,是一种更好的方法。(我很少使用 fancyverb,因此在写答案时我还没有意识到这个关键。;-))

思考\g@addto@macro通常使用(全局重新定义带有附加标记的宏)而不是(只要不是正数\local@addto@macro,重新定义就被限制在当前范围内)应该不会有问题。\globaldefs

我没有这样做,因为我倾向于不永久改变内核中的东西,以减少严重干扰其他软件包引入的更改的风险。

这些包之一可能是 inputenc 包:当使用 utf8 编码和 8bit-TeX 引擎时,inputenc 会使一些字符处于活动状态,而这些字符在以下情况下不应切换为类别代码 12(其他)显示逐字材料(因为它们被定义为“查看”以下字节/字符,以找出要传递给 .pdf 输出文件的多字节序列/unicode 字符的字形/字母),但可能应该在以下情况下切换到类别代码 12(其他)写作逐字逐句地写入外部文本文件(作为确保它们“按原样”写入而不是在写入时尝试扩展它们的一种手段)。

另一种方法可能是为活动&/ °/提供定义!,检查事物是否以逐字模式处理并相应地进行分叉(在逐字处理的情况下,提供相关活动角色的 catcode-12(other)-pendant)。有人知道一个安全/可靠/可靠的标准来检测是否发生逐字处理吗?(我即兴地想到了检查\do(应该等于\@makeother)的定义,但我怀疑这是否安全……)


在通过 inputenc 包处理 utf8 编码的输入文件的 8 位 TeX 引擎上,utf8 度数符号字符通常会产生一个字符代码为 194(十进制)的活动字符标记,后跟一个字符代码为 176(十进制)的活动字符标记。

因此,在通过 inputenc 包处理 utf8 编码的输入文件的 8bit-TeX 引擎上,当 fancyverb 的VerbatimOut环境将内容写入文件时,需要在\dospecials对环境内容进行标记之前,通过向列表添加指令来将这些字符切换为 catcode 12(其他),以防止扩展这些字符标记的尝试。

(我们希望在 8 位引擎上这些字符能按原样书写,并且在书写时不使用任何字符转换(.tcx 文件),将它们(其中一些)转换为 ^^ 符号或其他符号。)

至少在我的系统上,下面的代码都可以用 lualatex/xelatex (utf8/multibyte-character-engines) 和 pdflatex (8bit/single-byte-engine) 编译成功:

\documentclass{article}

\usepackage{iftex}
\newif\ifEightBitEngine
\ifXeTeX\EightBitEnginefalse\else
  \ifLuaTeX\EightBitEnginefalse\else\EightBitEnginetrue\fi
\fi

\makeatletter
\newcommand\exchange[2]{#2#1}
\newcommand\local@addto@macro[2]{%
  \expandafter\exchange\expandafter{\expandafter\toks@\expandafter{\the\toks@}}{%
    \toks@\expandafter{#1#2}\edef#1{\the\toks@}%
  }%
}%
\makeatother

\ifEightBitEngine
  \usepackage[T1]{fontenc}%
  \usepackage{textcomp}%
  \usepackage[utf8]{inputenc}%
\else
  \usepackage{fontspec}%
\fi

\usepackage{verbatim, fancyvrb}

\begin{document}

\begingroup

\makeatletter
% & is already in the specials-list
\local@addto@macro\dospecials{\do\!}
\ifEightBitEngine
   \newcommand\makeutfbyteother[1]{%
      \begingroup
      \lccode`~=#1\relax
      \lowercase{\endgroup\catcode`~}=12\relax
   }%
   \local@addto@macro\dospecials{\makeutfbyteother{194}}%
   \local@addto@macro\dospecials{\makeutfbyteother{176}}%
\else
  \local@addto@macro\dospecials{\do\°}%
\fi
\makeatother
% Now the changes to \dospecials are in effect.
% They need to be as both our own redefinitions are in effect and (active)
% characters actually forming the single bytes of multibyte-encoded 
% utf8-characters will be written to external file.
%\show\dospecials

\catcode`\&=\active
\long\def &#1&{\textbf{#1}}

\ifEightBitEngine\else
  \catcode`\°=\active
\fi
\long\def °#1°{\textbf{#1}}

\catcode`\!=\active
\long\def !#1!{\textbf{#1}}

&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

°Bar° in text.
\begin{VerbatimOut}{example-2.tex}
°Bar° in verbatim.
\end{VerbatimOut}

!Baz! in text.
\begin{VerbatimOut}{example-3.tex}
!Baz! in verbatim.
\end{VerbatimOut}

\endgroup

% Now the changes to \dospecials are not in effect any more.
% They don't need to be as both our own redefinitions are not in effect any more
% and characters will not be written to file.
%\show\dospecials

\section{This is \texttt{example-1.tex}:}

\verbatiminput{example-1.tex}

\section{This is \texttt{example-2.tex}:}

\verbatiminput{example-2.tex}

\section{This is \texttt{example-3.tex}:}

\verbatiminput{example-3.tex}

\end{document}

使用 fancyverb 的codes=-key,如下所示egreg 的回答,你也许可以做类似下面的事情,这(至少在我的系统上)也使用 lualatex/xelatex (utf8/multibyte-character-engines) 和 pdflatex (8bit/single-byte-engine) 都可以很好地编译

\documentclass{article}

\usepackage{iftex}
\newif\ifEightBitEngine
\ifXeTeX\EightBitEnginefalse\else
  \ifLuaTeX\EightBitEnginefalse\else\EightBitEnginetrue\fi
\fi

\ifEightBitEngine
  \usepackage[T1]{fontenc}%
  \usepackage{textcomp}%
  \usepackage[utf8]{inputenc}%
  \newcommand\saveactivechar[1]{%
    \begingroup
    \lccode`\~=#1\relax
    \lowercase{\endgroup\expandafter\let\csname utfbyte\romannumeral\expandafter`\string~\endcsname=~}%
  }%
  \newcommand\restoreactivechar[1]{%
    \begingroup
    \lccode`\~=#1\relax
    \lowercase{\endgroup\expandafter\let\expandafter~\expandafter=\csname utfbyte\romannumeral\expandafter`\string~\endcsname}%
  }%
\else
  \usepackage{fontspec}%
\fi

\usepackage{verbatim, fancyvrb}


\begin{document}

\catcode`\&=\active
\long\def&#1&{\textbf{#1}}

\ifEightBitEngine
   \saveactivechar{194}%
   \saveactivechar{176}%
\else
  \catcode`\°=\active
\fi
\long\def °#1°{\textbf{#1}}

\catcode`\!=\active
\long\def !#1!{\textbf{#1}}


&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

°Bar° in text.
\begin{VerbatimOut}[codes={\ifEightBitEngine\catcode194=12 \catcode176=12 \else\catcode`°=12 \fi}]{example-2.tex}
°Bar° in verbatim.
\end{VerbatimOut}

!Baz! in text.
\begin{VerbatimOut}[codes={\catcode`!=12}]{example-3.tex}
!Baz! in verbatim.
\end{VerbatimOut}

\section{This is \texttt{example-1.tex}:}

\verbatiminput{example-1.tex}

\section{This is \texttt{example-2.tex}:}

\begingroup
\ifEightBitEngine
  \restoreactivechar{194}%
  \restoreactivechar{176}%
\else
  \catcode`°=12 %
\fi
\verbatiminput{example-2.tex}
\endgroup

\section{This is \texttt{example-3.tex}:}

\begingroup
\catcode`!=12 %
\verbatiminput{example-3.tex}
\endgroup

\end{document}

您还可以自动保存和恢复当前分配给字符代码的类别代码以及具有该字符代码的活动字符的含义:

\documentclass{article}

\usepackage{iftex}
\newif\ifEightBitEngine
\ifXeTeX\EightBitEnginefalse\else
  \ifLuaTeX\EightBitEnginefalse\else\EightBitEnginetrue\fi
\fi

\ifEightBitEngine
  \usepackage[T1]{fontenc}%
  \usepackage{textcomp}%
  \usepackage[utf8]{inputenc}%
\else
  \usepackage{fontspec}%
\fi

\usepackage{verbatim, fancyvrb}

\newcommand\savechar[1]{%
  \begingroup
  \lccode`\~=#1\relax
  \lowercase{%
    \endgroup
    \expandafter\let\csname charmeaning\romannumeral\expandafter`\string~\endcsname=~%
    \expandafter\edef\csname charcatcode\romannumeral\expandafter`\string~\endcsname
  }{\the\catcode#1}%
}%
\newcommand\restorechar[1]{%
  \begingroup
  \lccode`\~=#1\relax
  \lowercase{%
    \endgroup
    {\expandafter}\expandafter\let\expandafter~\expandafter=\csname charmeaning\romannumeral\expandafter`\string~\endcsname
    \catcode\expandafter`\string~=\csname charcatcode\romannumeral\expandafter`\string~\endcsname\relax
  }%
}%

\begin{document}

\savechar{`\&}%
\catcode`\&=\active
\long\def&#1&{\textbf{#1}}

\ifEightBitEngine
   \savechar{194}%
   \savechar{176}%
\else
  \savechar{`\°}%
  \catcode`\°=\active
\fi
\long\def °#1°{\textbf{#1}}

\savechar{`\!}%
\catcode`\!=\active
\long\def !#1!{\textbf{#1}}


&Foo& in text.
\begin{VerbatimOut}{example-1.tex}
&Foo& in verbatim.
\end{VerbatimOut}

°Bar° in text.
\begin{VerbatimOut}[codes={\ifEightBitEngine\catcode194=12 \catcode176=12 \else\catcode`°=12\fi}]{example-2.tex}
°Bar° in verbatim.
\end{VerbatimOut}

!Baz! in text.
\begin{VerbatimOut}[codes={\catcode`!=12}]{example-3.tex}
!Baz! in verbatim.
\end{VerbatimOut}

\section{This is \texttt{example-1.tex}:}

\begingroup
\restorechar{`\&}%
\verbatiminput{example-1.tex}
\endgroup

\section{This is \texttt{example-2.tex}:}

\begingroup
\ifEightBitEngine
  \restorechar{194}%
  \restorechar{176}%
\else
  \restorechar{`\°}%
\fi
\verbatiminput{example-2.tex}
\endgroup

\section{This is \texttt{example-3.tex}:}

\begingroup
\restorechar{`\!}%
\verbatiminput{example-3.tex}
\endgroup

\end{document}

相关内容