Latex 用于'\开始{environment}…\end{environment}';

Latex 用于'\开始{environment}…\end{environment}';,latex,Latex,要使用剧本软件包输入一些对话,我必须使用 \begin{dialogue}{Johnny} Some dialogue. \end{dialogue} \begin{dialogue}{Jane} I see. \end{dialogue} 过了一会儿就有点乏味了。是否可以指定自定义命令,以便我可以使用 \dialogue{Johnny} Some dialogue. \dialogue{Jane} I see. 相反?试试以下方法: \newcommand{\dialogueline}[2

要使用
剧本
软件包输入一些对话,我必须使用

\begin{dialogue}{Johnny} Some dialogue. \end{dialogue}
\begin{dialogue}{Jane} I see. \end{dialogue}
过了一会儿就有点乏味了。是否可以指定自定义命令,以便我可以使用

\dialogue{Johnny} Some dialogue.
\dialogue{Jane} I see.
相反?

试试以下方法:

\newcommand{\dialogueline}[2]{\begin{dialogue}{#1} #2 \end{dialogue}}

% Usage example:
\dialogueline{Johnny}{Some dialogue.}  
\dialogueline{Jane}{I see.}  

事实上,你可以得到你想要的:

\newcommand{\dialogueline}{\begingroup\catcode`\^^M=12 \dialogueline@EOL}
{\catcode`\^^M=12\gdef\dialogueline@EOL#1#2^^M{\begin{dialogue}{#1}#2\end{dialogue}\endgroup}}
此代码需要被
\makeatletter
/
\makeatother
(编辑:这意味着您将
\makeatletter
放在定义之前,将
\makeatother
放在定义之后),或者放在
.sty
文件中。请注意,名为
dialogue
的环境定义了名为
\dialogue
的命令,因此您需要一个不同的名称。不要更改格式

它的工作方式是,
\dialogueline
是一个不带参数的命令,而是扩展到多个序列。首先,一个组开始标记,将后面的内容放在它自己的范围内。其次是
\catcode`^^M=12
序列。LaTeX为每个字母分配一个数字,表示字母的类型。例如,反斜杠是catcode 0,即命令名构造函数;字母为catcode 11;非字母打印字符(如at符号)为catcode 12。这个序列使换行符
^^M
具有catcode 12,因此我们可以与它交互。最后,我们写出命令
\dialogueline@EOL
,它完成重物的搬运

接下来,我们定义
\dialogueline@EOL
。我们在换行符为catcode 12的组中执行此操作,就像在展开
\dialogueline
时一样。请注意,这就是为什么不能用换行符打断第二行,因为它将被解释为文本。接下来,我们定义
\dialogueline@EOL
接受两个参数,以换行符结尾;它通过将第一个参数(用大括号传递)作为参数传递给
对话
环境,并将第二个参数(第一行之后和行尾之前的所有内容)作为环境主体来展开。最后,
\dialogueline@EOL
结束在
\dialogueline
中打开的组,因此对
^^M
的catcode的更改在其他任何地方都不可见。考虑到这一点,你可以写作

\dialogueline{Johnny} Some dialogue.
\dialogueline{Jane}   I see.

一切都应该正常。

如果假设每个对话框占用一个段落(通常,它以双行段落分隔符开始和结束),那么还有另一种方法可以让
\dialogue
只接受一个参数:

\newif\indialog \indialogfalse \def\dialogue#1{\ifindialog \end{dialogue}#1\begin{dialog}\else \everypar={\end{dialogue}\indialogfalse \everypar={}}#1\indialogtrue\begin{dialogue} \fi} \newif\indialog\indialogfalse \def\dialog{\ifindialog\end{dialog}\1\begin{dialog}\else \everypar={\end{dialogue}\indialogfalse\everypar={}}\1\indialogtrue\begin{dialogue} \fi}
这段代码有点脏,不太晚-它设置
\everypar
,而不关心它现有的内容-Latex有更干净的抽象,我已经忘记了,但原则应该很清楚。

取决于您使用的编辑器,你可能还想看看snippets软件包。+1这是一个非常有趣的问题。这是一个很好的答案,但如果有人知道如何复制原始海报所要求的确切格式,那就太好了。我认为这是你能得到的最接近海报想要的内容。文本周围必须有大括号,以便LaTeX知道在哪里正确放置
\begin{dialogue}
\end{dialogue}
。此外,我还使用了
\dialogueline
,以防已经有另一个名为
\dialogue
的命令,但如果不是这样的话,海报可以将
\dialogueline
替换为
\dialogue
,前提是它不会导致错误。这相当聪明。直到现在我才知道
\catcode
。虽然我的解决方案适用于支架内的任何东西,您的将适用于一行程序,并且更接近询问者请求的语法。技巧实际上不是关于CATCode,而是关于
\def
中的模式匹配:您还可以执行类似
\gdef的操作\dialogueline@EOL#1:#2^^M
能够写
\dialogueline约翰尼:一些对话。
。catcode开关的作用是使行尾不仅被视为空格字符并被忽略,而是被视为可匹配字符。你是对的,这可能会取缔一些有效的字符串(尽管其中一些可以通过将匹配的字符串隐藏在大括号中来实现,例如
\dialogueline{Alexander:the Great}:Die!
),但这对于快捷方式和嵌入式DSL来说很好。真的很好。就像你说的那样。谢谢你的详细解释!事实上,当我使用\MakeTother时,我遇到了一个“使用\dialogueline与它的定义不匹配”错误,但它与\MakeTletter一起工作很好。很抱歉,我没有澄清这一点——定义必须在
\MakeTother
之后和
\MakeTother
之前。(前者将
@
的catcode更改为字母的catcode,因此它可以是控制序列名称的一部分;后者将其更改回原来的catcode。)这很聪明,我以前从未见过这种技术。