强制 \endlinechar 在最后一行结束前重置

强制 \endlinechar 在最后一行结束前重置

我正在创建一个宏,它应该将其参数作为文字字符串写入外部文件。这是它的当前状态:

\newcommand{\mycmd}{%
    \begingroup
    \let\do\@makeother \dospecials
    \endlinechar=`\^^J
    \catcode`\^^M=9
    \catcode`\^^I=12
    \catcode`\ =12
    \catcode`\{=1
    \catcode`\}=2
    \@mycmd
}

\long\def\@mycmd#1{%
    \endgroup
    \newwrite\myfile
    \immediate\openout\myfile{file.out}%
    \immediate\write\myfile{\unexpanded{#1}}%
    \immediate\closeout\myfile
}

其用法如下:

\mycmd{
some text ...
text on new line
    this text will be indented
et cetera
}

这对于在文件中写入文本来说是正确的,但是在宏的最后一行(即带有 的行})之后,会显示一个 Omega 字符,我想这是由于仍然是 的别名所致。\endlinechar10

我知道我可以简单地用评论来结束该行,但我打算与其他人分享此代码,并且我想自动修复。

答案1

\endlinechar只要 TeX 需要获取一行输入,就会插入,但不会进行标记。

因此,您可以声明,在组结束后,\endlinechar(仍然是^^J)处于活动状态,其定义只是恢复正常的类别代码。

\documentclass{article}

\makeatletter
\newcommand{\mycmd}{%
    \begingroup
    \let\do\@makeother \dospecials
    \endlinechar=`\^^J
    \catcode`\^^M=9
    \catcode`\^^I=12
    \catcode`\ =12
    \catcode`\{=1
    \catcode`\}=2
    \@mycmd
}

\newwrite\myfile % must go outside the macros!

\newcommand{\@mycmd}[1]{%
    \immediate\openout\myfile{\jobname.out}%
    \immediate\write\myfile{\unexpanded{#1}}%
    \immediate\closeout\myfile
    \endgroup\@check@endline
}
\newcommand{\@check@endline}{%
  \begingroup\lccode`~=`^^J \lowercase{\endgroup\def~}{\@makeother\^^J}%
  \catcode`^^J=\active
}

\makeatother

\begin{document}

Text before.
\mycmd{
some text ...
text on new line
    this text will be indented
et cetera
}
This is not gobbled.

\end{document}

当心你想要\newwrite里面\@mycmd或者每次调用时都会分配一个新的流\mycmd

我也建议不是推行这一策略:编辑对于如何应对用户发出的换行符有非常不同甚至奇怪的想法。

这个宏的作用是什么\@check@endline?它设置^^J为一个活动字符,赋予它“将类别代码改^^J回 12”的含义。因此该字符消失了,并且它处于活动状态也被遗忘了。

答案2

你的解释对我来说似乎是正确的。如果 0 ≤  ≤ 255,则在每一行后附加\endlinechar 一个具有 TeX 内部代码的字符\endlinechar很早,甚至在该行开始标记化之前。在您的示例中,一旦\@mycmd展开,TeX 就会读取并标记输入,直到它有一个参数,在本例中,该参数一直到结束符}。因此,包含此字符的行将获得从 获得的终止符\endlinechar=`\^^J,即具有 TeX 内部代码 10 的字符。

只有在此之后,\@mycmd宏调用才会被其替换文本(以 开头)所替换,\endgroup并且只有在此之后才会\endgroup执行,从而恢复 的正常值\endlinechar

由于 TeX 内部代码为 10 的字符的 catcode 是 12 又称“其他”(这是纯 TeX 和 LaTeX 中的默认设置,在示例中没有更改),当添加的字符被标记时,它会产生一个 (10, 12) 字符标记,这会导致当前字体中的字符 10(此处的编码为 OT1)被写入输出文件,这确实是(参见texdoc encguide第 19 页):

在此处输入图片描述

以下代码使用带分隔参数的宏来删除不需要的 (10, 12) 显式字符标记:

\documentclass{article}

\makeatletter
% \newwrite out of the macro def., as egreg recommended
\newwrite\myfile

\newcommand{\mycmd}{%
    \begingroup
    \let\do\@makeother \dospecials
    \endlinechar=`\^^J
    \catcode`\^^M=9
    \catcode`\^^I=12
    \catcode`\ =12
    \catcode`\{=1
    \catcode`\}=2
    \my@cmd
}

\newcommand{\my@cmd}[1]{%
    \endgroup
    \immediate\openout\myfile{file.out}%
    \immediate\write\myfile{\unexpanded{#1}}%
    \immediate\closeout\myfile
    \my@normalizeEndline
}

\@ifdefinable{\my@normalizeEndline}{%
  \def\my@normalizeEndline#1^^J{#1}%
}

\makeatother

\begin{document}

\mycmd{
  some text ...
  text on new line
  this text will be indented
  et cetera
}
% \mbox{}% Uncomment if you want an output file (PDF or DVI) to be written

\end{document}

注意:使用此技术时,用户不能%在 后放置},否则 TeX 会进一步寻找 (10, 12) 显式字符标记。另一种可能性(也有其缺点)是使用\@ifnextchar^^J{\@gobble}{}%\my@normalizeEndline不是\my@cmd

相关内容