问题背景:
想通过在环境中修改回车的行为,化简代码。
例如,exam-zh 中的选择题代码如下
\begin{choices}
\item 选
\item 项
\end{choices}
思考能否优化 choices 环境,使 每行 自动变成一个条目,不用再写 \item
,
上述选择题的代码精简为:
\begin{choices}
选
项
\end{choices}
我的构思如下,(为了方便查看理解,用\n
表示回车符)
先定义一个以回车符为结尾的命令: \everyEnter#1\n
,一行的内容就是其参数
\def\everyEnter#1\n{\doSomethingWith{#1}%分离出一行的内容进行处理
\@ifnextchar\end{\relax}{\everyEnter}}%如果回车后是 \end 就休息,否则重复 \everyEnter
\newenvironment{makeEnterMacro}{\catcode`\^^M\active \everyEnter}
{\catcode`\^^M=10}
然而,尝试在 newenvironment 改变 回车行为问题失败,
请大佬指点迷津
MWE 如下
\documentclass[UTF8]{ctexart}\pagestyle{empty}
\begin{document}
\section{改变回车行为示例}
\catcode`\^^M\active
\let^^M\TeX\relax
让回车符变成宏,可自定义
\def^^M{我是回车\par}
\catcode`\^^M=10 % 恢复正常回车
\section{在环境中 手工 改变回车行为}
\begin{center}
\catcode`\^^M\active \let^^M\LaTeX\relax
\end{center}
环境外,利用环境限制 回车 的修改范围
\section{问题来了:定义一个改变回车的环境,怎么就报错了呢}
\newenvironment{makeEnterMacro}{\catcode`\^^M\active \let^^M\LaTeX\relax}{\catcode`\^^M=10}
% newenvironment 有问题,以下瞎改
%\def\cc{\protect\catcode`\^^M=13\relax\def\zz##1^^M{【##1】}\zz}
%\def\endcc{\catcode`\^^M=10}
%\begin{makeEnterMacro}
此环境
怎么就出错了呢
%\end{makeEnterMacro}
\end{document}
这个问题本质上是:
寻求一种将 字符串 分割成 列表
(或者说,在 LaTeX 中实现一种简约的列表数据结构)
供 maping 的方法
这个问题涉及到 TeX 的内部处理,最好读过 TeX by topic 的第 1、2 章
首先说说 TeX 是怎样处理一个输入行的。
TeX 从文件中读入一行,去掉行终止符(catcode=5),去掉行尾空格,插入 \endlinechar
,一般为 return 字符(ASCII 13)。
然后逐个读取字符,当遇到控制词(转义符+一串catcode=11的字符)或控制空格(转义符+空格字符ASCII 32)时进入状态 S,此状态后续的空格符(catcode=10)被忽略,如果在这个状态遇到行终止符,则连同这个行终止符及本行未读入的字符都被忽略了。
问题出现在 \newenvironment
这一行。
当读到控制序列 \let
后,进入状态 S,随即遇到行终止符 ^^M
(ASCII 13),它连同这行未处理的字符都被忽略了。所以正常情况下,一直到文件的结束 TeX 都没有遇到与 {
匹配的那个 }
。
但为什么你的没有报错呢?是因为你之前把 ^^M
的 catcode 设置为 10 了,这是空格的 catcode,而不是行结束符(catcode=5)的。如果你把之前的 ^^M
的 catcode 设为 5,就会得到 low-level 的错误。
为了正确定义这个环境,需首先修改 ^^M
的 catcode,然后定义完再恢复:
\catcode`\^^M=13 % 这里最好使用注释符
\newenvironment{makeEnterMacro}{\catcode`\^^M\active \let^^M\LaTeX\relax}{\catcode`\^^M=5 }% 同上
\catcode`\^^M=5 % 同上
MWE:
\documentclass[UTF8]{ctexart}\pagestyle{empty}
\begin{document}
\catcode`\^^M=13 %
\newenvironment{makeEnterMacro}{\catcode`\^^M\active \let^^M\LaTeX\relax}{\catcode`\^^M=5 }%
\catcode`\^^M=5 %
\begin{makeEnterMacro}
此环境
怎么就出错了呢
\end{makeEnterMacro}
\end{document}
得到了想要的结果:
另外,如果你更新到了最新的 LaTeX 发行版(2022-06-01),则可以直接修改 \obeyedline
,然后使用 \obeylines
:
\makeatletter
\newenvironment{mychoices}
{\def\obeyedline{\@ifnextchar\end{\par}{\item}}\obeylines
\begin{itemize}}
{\end{itemize}}
\makeatother
\begin{mychoices}
选
项
\end{mychoices}
???? 精辟,通透 ????