\newcommand 带有 \begin{}[] 文本和 \end

\newcommand 带有 \begin{}[] 文本和 \end

我正在尝试创建一个名为 \codeR 的新命令:

\codeR{This will appear with a code format}

这可能有助于我避免每次都输入所有 \begin{lstlisting}[language=R] 和 \end{lstlisting} 命令:

\usepackage{listings}

\begin{document}
\begin{lstlisting}[language=R]
     This will appear with a code format
\end{lstlisting}
\end{document}

我尝试了以下操作:

\newcommand{\codeR}[1]{
\begin{lstlisting}{language=R}
{#1}
\end{lstlisting}
}

但不起作用。你能帮我吗?谢谢。

答案1

这可能是更短的方法。对于与 相关的重要事实\scantokens,我参考了 @UlrichDiez 的详细解释回答

\documentclass{article}
\usepackage{listings}
%\usepackage[T1]{fontenc}

\makeatletter
\newcommand\codeR{\begingroup
                  \obeylines
                  \let\do\@makeother\dospecials
                  \catcode`\{ 1 \catcode`\} 2
                  \@codeR}%
\newcommand\@codeR[1]{\endgroup\newlinechar`\^^M
  \scantokens{\begin{lstlisting}[language=R]%
#1}% notice that #1 incorporates an initial and final EOL
\end{lstlisting}%
\newlinechar`^^J }% back to LaTeX's default
\makeatother

\begin{document}
You asked for it. You got it.

\begin{lstlisting}[language=R]
   This will appear with a {\code} format (also ^^41)
1234567890123456789012345678901234567890
     This will appear with a {\code} format
          This will appear with a {\code} format
\end{lstlisting}

A

\codeR{
   This will appear with a {\code} format (also ^^41)
1234567890123456789012345678901234567890
     This will appear with a {\code} format
          This will appear with a {\code} format
}
B

\begin{lstlisting}[language=R]
   This will appear with a {\code} format (also ^^41)
1234567890123456789012345678901234567890
     This will appear with a {\code} format
          This will appear with a {\code} format
\end{lstlisting}
A

\codeR{
   This will appear with a {\code} format (also ^^41)
1234567890123456789012345678901234567890
     This will appear with a {\code} format
          This will appear with a {\code} format
}

B
\end{document}

需要考虑的事项:

  • 如上所示,我更喜欢使用更清晰的语法

    \codeR{
    first line of listing
    ....
    last line of listing
    }
    
  • 非环境形式中,内容中的括号必须成对。

  • 我完全忽略了非 ascii 字符的问题(现在 LaTeX 默认使用 utf8),因为这已经很困难了listings,而且我不知道那里问题的当前状态。

  • 总而言之,人们并没有完全看到仅仅稍微短一点的输入语法形式的好处......因为 LaTeX\begin...\end无论如何都充满了,并且任何合理的编辑器都会有快捷方式来插入环境,比如 Emacs 中的 C-cC-e。

  • 图像显示,删除 environment/codeR 之后和 A 或 B 上方的空行后,会出现缩进抑制效果,这两种情况都有这种效果,因此行为相同。

在此处输入图片描述

答案2

\newcommand一旦存在易碎内容,A就不起作用。相反,请使用\lstnewenvironment

\documentclass{article}
\usepackage{listings}

\lstnewenvironment{codeR}{\lstset{language=R}}{}

\begin{document}
\begin{codeR}
     This will appear with a code format
\end{codeR}
\end{document}

答案3

(确保使用某种 8 位编码对其进行编码,例如 latin1。)

\documentclass{article}
\usepackage{listings}

\makeatletter
%%=================================================================
%% Copyright (C) 2007 - 2018 by Ulrich Diez ([email protected])
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public Licence (LPPL), either
%% version 1.3 of this license or (at your option) any later
%% version. (The latest version of this license is in:
%% http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included
%% documentation nor for any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%=================================================================
% Implement stuff for reading arguments "verbatim":
%
% Syntax of \UDcollectverbarg:
%
%   \UDcollectverbarg{<^^M-replacement>}{<Mandatory 1>}{<Mandatory 2>}<verbatim-Arg>
%
% yields:
%
%   <Mandatory 1>{<Mandatory2>{<verbatim-Arg>}}
%
% Syntax of \UDconcatverbarg:
%
%   \UDconcatverbarg{<^^M-replacement>}{<Mandatory 1>}{<Mandatory 2>}<verbatim-Arg>
%
% yields:
%
%   <Mandatory 1>{<Mandatory2><verbatim-Arg>}
%
% with each character ^^M (usually=\endline-char) replaced by
%   token-sequence <^^M-replacement>
%
% The Mandatory-Arguments are mandatory. If they consist of several
% tokens, they must be nested into catcode-1/2-character-pair / braces.
% If reading is necessary, they will be read under normal catcode-
% conditions.
% The verbatim-Arg is also mandatory. It will be read under
% verbatim-catcode-conditions. If its first character is a brace,
% it will be "assumed" that the argument is nested into braces.
% Otherwise it will be assumed, that the argument is delimited
% by the first character - like the argument of \verb.
%
% Empty-lines will not be ignored.
%
% By nesting calls to \UDcollectverbarg within \UDcollectverbarg's first
% argument, you can collect "verbatim-arguments" within its second
% argument.
%
% E.g.,
%
%   \UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}}% <- Mandatory 1
%                {<actionB>}%                     <- Mandatory
%                <verbatim-Arg1><verbatim-Arg2><verbatim-Arg3>
%
% yields:
%
%  \UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}% <- Mandatory 1
%               {<actionB><verbatim-Arg1>}%        <- Mandatory 2
%               <verbatim-Arg2><verbatim-Arg3>
%
% yields:
%
%  \UDcollectverbarg{<^^M-replacement>}{<actionA>}% <- Mandatory 1
%               {<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}}% <- Mandatory 2
%               <verbatim-Arg3>
%
% yields:
%
%  <actionA>{<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}}
%
% Assume <actionA> = \@firstofone -> equals:
%
%     \@firstofone{<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}}
%
%    yields:
%
%     <actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}
\begingroup
\catcode`\^^M=12 %
\@firstoftwo{%
  \endgroup%
  \newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
  \newcommand*\@UDEndlreplace{}%
  \long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
    \@CheckWhetherNull{#3}%
    { #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
  }%
}{}%
\newcommand\UDcollectverbarg{\@UDverbarg{\@UDcollectverbarg}}%
\newcommand\UDconcatverbarg{\@UDverbarg{\@UDconcatverbarg}}%
\newcommand\@UDverbarg[4]{%
  \@bsphack
  \begingroup
  \let\do\@makeother\dospecials
  \catcode`\{=1 %
  \catcode`\ =10 %
  \@ifnextchar\bgroup
  {\catcode`\}=2 \@@UDverbarg{#1}{#2}{#3}{#4}{}}%
  {\do\{\@@UDverbarg{#1}{#2}{#3}{#4}}%
}%
\newcommand\@@UDverbarg[5]{%
  \do\ %
  \catcode`\^^M=12 %
  \long\def\@tempb##1#5{%
    \edef\@tempb{##1}%
    \@onelevel@sanitize\@tempb
    \expandafter\UDEndlreplace\expandafter{\@tempb}{#2}{\def\@tempb}%
    \expandafter#1\expandafter{\@tempb}{#3}{#4}%
  }%
  \@tempb
}%
\newcommand\@UDcollectverbarg[3]{%
  \endgroup
  \@esphack
  #2{#3{#1}}%
}%
\newcommand\@UDconcatverbarg[3]{%
  \endgroup
  \@esphack
  #2{#3#1}%
}%
\newcommand\@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begingroup
\makeatletter
\catcode`\^^M=12 %
\catcode`\/=0 %
\catcode`\\=12 %
/@firstofone{%
  /endgroup%
  /newcommand/codeR{/UDconcatverbarg{^^M}{/innercodeR}{}}%
  /newcommand/innercodeR[1]{%
    /begingroup%
    /newlinechar=/endlinechar%
    /scantokens{%
       \endgroup%
       \begin{lstlisting}[language=R]
       #1
       \end{lstlisting}%
    }%
  }%
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

You asked for it. You got it.

I definitely prefer the environment because with the command the indention
of the first line of code is a bi confusing at first glimpse.

\begin{lstlisting}[language=R]
   This will appear with a code format
1234567890123456789012345678901234567890
     This will appear with a code format
          This will appear with a code format
\end{lstlisting}


\codeR|   This will appear with a code format
1234567890123456789012345678901234567890
     This will appear with a code format
          This will appear with a code format|


\codeR{   This will appear with a code format
1234567890123456789012345678901234567890
     This will appear with a code format
          This will appear with a code format}

\end{document}

在此处输入图片描述


使用指南\codeR

内部\codeR确实使用\scantokens。由于工作方式的微妙性\scantokens,有必要\codeR在 verbatim-catcode-régime 下读取输入并标记构成其参数的标记。因此,\codeR在获取(并且在此——这是我们的希望——必须从输入文件中读取输入以标记构成它的标记)其参数并将该参数传递给它之前,切换到 verbatim-catcode-régime,\scantokens然后将其包装在 lstlisting 环境周围,然后重新处理并在此重新标记整个内容。

基本事实:

(La)TeX 以所谓的 token 为基础。token 是一种数据结构。

但是,当您将 (La)TeX 视为生产 .pdf 文件等的工厂时,您可以将标记视为漂亮的小闪闪发光的物品,它们在该工厂的装配线开始时被放到装配线上,然后被运送到该工厂的更深层领域。许多人称该装配线为“标记流”。因此,当 (La)TeX 读取您的 .tex 输入文件时,它会从该文件获取一组指令,以将这些漂亮的小闪闪发光的标记放在装配线的开头。 (La)TeX“查看”输入文件并决定/选择将哪些标记放在装配线的开头/将哪些标记插入标记流的源头。选择受所谓的类别代码的影响。 (La)TeX 在输入文件中可能看到的每个字符都有一个所谓的类别代码。分配给输入字符的类别代码决定了在 .tex 输入文件中看到该字符时将哪个标记放入装配线上/标记流中。例如,当输入文件中的 (La)TeX 看到当前分配了类别代码 0 的字符时(通常类别代码 0 仅分配给反斜杠字符\),指令将使用此字符从后面的输入字符中收集控制序列标记的名称,然后将相应的控制序列标记放入装配线上。例如,当 (La)TeX 没有收集控制序列标记的名称并在输入文件中找到字符“A”时,而“A”当前已分配类别代码 11(字母),它会将一个明确的字符标记放到装配线上,其类别代码为 11(字母),字符代码为 65。(内部 (La)TeX 确实以 ASCII 表示所有可能的字符,即编码范围从 0 到 255,其中 0 到 127 的范围对应于 ASCII,而 128 到 256 的范围取决于用户端/运行 (La)TeX 的计算机平台端流行的 8 位编码。“A”在 ASCII 中的数字为 65。)

然后工厂里还有另一个站。那就是扩展站。在这里,(La)TeX 查看装配线带到扩展站的标记,并删除一些标记并用其他标记替换它们。执行此操作的规则来自⟨替换文本⟩宏定义和可扩展 TeX 基元的含义。例如,\romannumeral是一个可扩展的 TeX 基元,其扩展结果是将被视为数字表示的标记序列替换为被视为这些数字表示的标记序列,就像罗马人写数字的方式一样。

因此,代币可以通过两种方式产生:

  1. 当 (La)TeX 读取并标记输入时。这是类别代码适用的时刻。

  2. 当 TeX 在扩展过程中根据给定的规则用其他标记替换标记时,⟨替换文本⟩宏定义和可扩展 TeX 原语的含义。

请注意,这\codeR确实依赖于在 verbatim-category-code-régime 下对其参数进行标记。

这意味着你应该使用\codeR

  • 它也无法通过其他宏传递其参数。这是因为参数是从输入中读取的,并且不是在执行时进行标记\codeR,而是在扩展这些其他宏时进行标记。
    这种情况反过来意味着,构成参数的标记\codeR在错误的 catcode-régime 下进行标记的可能性很高。

    (乍一看,事情似乎无论如何都会顺利进行。但是,有一些微妙之处与 eTeX 原语的\scantokens工作方式有关:

    \scantokens模拟将未扩展的写入标记写入文本文件,然后读回并重新标记该文本文件。使用 (La)TeX 将未扩展的写入标记写入文本文件时,有一些微妙的方面:

    例如,在控制字后面总会插入一个尾随空格。

    例如,类别代码 6(参数)的显式字符标记(即哈希值)在未扩展写入文本文件时将始终加倍。

    当在未扩展写入期间遇到明确的字符标记,其字符代码(以 (La)TeX 的内部字符代码表示形式(即 ASCII)表示)等于整数参数的值\newlinechar时,(La)TeX 将不会写入该字符,但会将“换行符”(LF 或 CR 或 CR+LF;取决于您的计算机平台)写入相关的文本文件中。

    另外,在输入中还有一种微妙的^^符号来表示其他字符。
    输入文件中的-notation ^^-thingie 是输入文件中类别代码为 7(数学上标)的两个相等字符序列,后跟一个 ASCII 字符或两个(小写)十六进制数字。通常^具有类别代码 7(数学上标)。
    当在读取和标记输入时遇到^^-notation-thingie 时,(La)TeX 会将字符标记放入标记流中。例如,当在输入中遇到序列 时^^41,(La)TeX 会将其视为输入字符A—A = 65(十进制)= 41(十六进制)(ASCII ;-) —并将类别代码为 11(字母)且字符代码为 65(十进制)的字符标记放入标记流中。
    完成此操作后,(La)TeX 不再知道它是因为在输入文件中遇到了 ^^ 符号还是因为在输入文件中遇到了通常的符号而这样做的。当根据标记流对文件进行非扩展写入时,TeX 可能会写入相关字符标记的通常表示。
    对于 .tex 输出应该与输入完全相同的代码列表,这可能会导致 ^^ 序列意外转换为其他内容。例如,^^41可能会转换为A

    因此,必须确保 (La)TeX 在\scantokens执行“未扩展书写”部分时不会执行此类微妙的操作。确保不会执行此类操作反过来又通过确保 (La)TeX 不会遇到执行此类操作的情况来实现。这又通过切换到逐字分类代码制度来实现其中没有字符具有类别代码 6(参数),并且其中没有字符具有类别代码 0(转义),并且其中没有字符具有类别代码 10(空格),并且其中没有字符具有类别代码 7(数学上标)在让 (La)TeX 读取并标记输入之前它应以逐字代码清单的形式进行处理。

    这样,读取和标记输入永远不会产生控制字标记(此后在\scantokens' 未扩展写作部分期间会插入不需要的空格),永远不会产生类别代码 6(参数)的字符标记(在\scantokens' 未扩展写作部分期间会加倍),永远不会导致 (La)TeX 采用类别代码 7(数学上标)的字符序列进行 ^^ 符号表示(在\scantokens' 未扩展写作部分期间可能会产生非 ^^ 表示)。没有类别代码 10(空格)的字符具有很好的副作用,即从输入中标记的几个连续空格不会折叠成一个空格标记。)

  • 也不会以传递参数的方式传递由于使用错误的 catcode-régime 标记扩展而产生的标记⟨替换文本⟩. 根据规则交付的代币⟨替换文本⟩⟨定义⟩是按照读取和标记定义时当前的类别代码机制进行标记的标记副本。这是错误的类别代码机制的可能性也很高。

始终确保的参数\codeR必须从输入中读取并在执行时进行标记\codeR

例如,不要做

\newcommand\macro[1]{something fancy \codeR{#1} more fanciness}
...
\macro{some code \relax##}

\macro展开时,参数将在非逐字分类代码制度下读取和标记。然后该参数被传递给\codeR。但\codeR反过来需要在逐字分类代码制度下标记的参数。所以这是一个问题。
(由于\scantokensunexpanded-writing-part 的微妙操作,例如在控制字后面放置空格和将 catcode-6-hashes 加倍,输出将类似于some code \relax*&langle;space&rangle;*####

例如,不要做

\newcommand\SomeConstantCodeR{\codeR{I do need this snippet often \relax##}}.
...
\SomeConstantCodeR

同样:定义文本在定义时被标记化,因此\relax将是一个控制字标记,而不是一系列显式字符标记,而哈希将是 catcode 6(参数)的显式字符标记。前者将导致在执行其未展开的写入部分时在xof\relax和第一个#of之间插入尾随空格。后者在扩展时将减少为一个哈希。剩余的单个哈希在执行其未展开的写入部分时又会加倍。##\scantokens\SomeConstantCodeR\scantokens

如果你愿意,你可以这样做:

\newcommand\fanythingsbeforecode[1]{something fancy #1 \codeR}
 ...
\fanythingsbeforecode|This actually is the code.|

您可以这样做,因为扩展\fanythingsbeforecode不会导致标记稍后可能作为参数处理的内容\codeR

相关内容