我该如何在纯 TeX 中定义一个字符来开始和结束一个环境?

我该如何在纯 TeX 中定义一个字符来开始和结束一个环境?

在 中TeX,数学模式的开始和结束使用相同的符号,即$。假设我想开始和结束这样的环境,也许使用斜体文本,使用字符*,如下所示。代码*this is italic*将排版此文本为斜体。我尝试了以下解决方案,但是没有效果。

\catcode`*\active
\def*#1{\bgroup\it#1\egroup}
*this is italic*
\bye

我也尝试过

\catcode`*\active
\newif\ifitalic
\def*#1{\ifitalic\egroup\italicfalse\else\italictrue\bgroup\it#1\fi}
*this is italic*
\bye

但他们都抛出了错误

Runaway argument?
! Paragraph ended before * was complete.

我究竟做错了什么?

答案1

您的问题是,由于您说,即 是未分隔的参数,因此您的宏*仅读取单个后续标记(忽略空格后)。 的第一次使用会到达,而第二次使用(在短语末尾)会到达(如果后面有空行),结果是“段落在 \par 之前结束”,因为未定义为。如果没有空行(您的示例中正是如此),则扫描到,结果是“禁止的控制序列”,因为定义为纯 TeX 中的。\def*#1{...}#1*t#1\par#1*\long\bye\bye#1\bye\outer

您可以定义\startit不带参数的“切换宏”,如下所示:

\def\startit{\bgroup \let\startit=\egroup \it}

\catcode`*=13
\def*{\startit}

Test *this is italic*
\bye

第一次使用*启动组,选择斜体字体并重新定义\startit\egroup。第二次使用*(在短语末尾)\startit以 含义运行\egroup并关闭组(现在未选择斜体字体)。此外,\startit之后 恢复其原始含义\egroup,因此下次可能*再次打开斜体文本。

*Egreg 展示了如何将斜体含义和**粗体含义结合起来的示例。此外,**斜体不执行任何操作,而*粗体选择粗体斜体。通过以下七行代码可以实现相同的行为:

\font\bi=cmbxti10

\catcode`\*=13
\def*{\activeast}
\def\activeast{\futurelet\next\aastA}
\def\aastA{\ifx*\next \expandafter \startbf \else \startit \fi}
\def\startit{\bgroup \def\startbf*{}\let\startit=\egroup \it}
\def\startbf*{\bgroup \let\it=\bi \def\startbf*{\egroup}\bf}

Hello, *th**i**s* is a **test, *to see* whether** it works.

\bye

请注意,该代码比 egreg 的 34 行代码紧凑得多。

答案2

以下是 Bruno Le Floch 代码的“解释”https://tex.stackexchange.com/a/15374/4427

\font\bfit=cmbxti10

\catcode`@=11

% boilerplate
\long\def\@gobble#1{}
\long\def\@firstofone#1{#1}

\def\star@out{%
  \star@ifnext{\bgroup\bf\let\star@current\star@inbf\@gobble}%
              {\bgroup\it\let\star@current\star@init}%
}
\def\star@inbf{%
  \star@ifnext{\egroup\@gobble}{\bgroup\bfit\let\star@current\star@initbf}%
}
\def\star@init{%
  \star@ifnext{\bgroup\bf\let\star@current\star@initbf}{\egroup}%
}
\def\star@initbf{\star@ifnext{\egroup\@gobble}{\egroup}}
\let\star@current\star@out

\def\star@ifnext#1#2{%
  \def \reserved@a {#1}%
  \def \reserved@b {#2}%
  \futurelet \@let@token \star@ifnext@aux 
}
\begingroup
\catcode`\*=13
\@firstofone{\endgroup
  \def*{\star@current}
  \def\star@ifnext@aux{%
    \ifx \@let@token *\let \reserved@c \reserved@a 
    \else             \let \reserved@c \reserved@b 
    \fi 
    \reserved@c
  }
}
\catcode`@=12

\catcode`\*=\active

Hello, *th**i**s* is a **test, *to see* whether** it works.

\bye

在此处输入图片描述

答案3

使用字符*作为参数分隔符。

\catcode`\*=\active
    \def*#1*{\bgroup\it#1\egroup}
    *this is italic*, but this isn't
\bye

相关内容