在宏主体中,很容易忘记命令行末尾的\relax
或。例如,在编写%
\def\myMacro{
\invokeX
\invokeY{}
\invokeZ
}
必须在第一行和第三行末尾添加空格吞噬器,但第二行、第四行和第五行末尾可以不添加。
简单的全局搜索/替换{$
by{%
将修复第一行等遗漏,并且不太可能添加多余的吞食者。但是,全局搜索/替换}$
by}%
也会在第五行后添加一个百分号。
为了 Google 搜索访问者的利益,让我写下vi
这些搜索的命令:
:%s/{$/{%/ :%s/}$/}%/
但正如我提到的,这些并不完美,并且可能无法处理其他棘手的情况。
所以,我的问题是:你能做得更好吗?也许有一个巧妙的重新定义\def
可以消除这些丑陋的添加的需要,或者也许有其他一些自动机制可以警告这些潜在的错误?
答案1
我写了一些代码来检查一段代码。它计算 的参数中出现了多少个空格以及多少个空格+行尾字符\cnel
,并将其显示到终端。它还运行代码:这样,就不会太混乱。
% Should print 1 and 4.
\cnel{
\def\foo{b ar
}
}
% Just to stop the run (press <enter>)
\read-1 to\dummy
% Should print 0 and 0, because there is no space nor end-of-line.
\cnel{%
\show\foo
}
诀窍是
使用
\scantokens
各种 catcode 设置来读取参数,以识别行尾字符:忽略或空格。我们首先需要使用 catcode other 来读取它,因为“忽略”它会消失,而“空格”它会变得与真正的空格无法区分。使用
\lowercase
将空格转换为其他特点(即^^S
),然后\detokenize
,并搜索细绳^^S
(该字符串本身是通过对小写空格进行去标记而生成的。)
。
% `cnel` = `check if no end-line`.
%
\catcode`\@=11\relax
\newcount\cnel@count
\def\cnel{%
\begingroup%
\catcode\endlinechar=12\relax%
\cnel@aux%
}
\newcommand{\cnel@aux}[2][\^^S]{%
% Set spaces to lowercase to the first, optional, argument (default ^^S).
\lccode`\ `#1%
% First we count the number of spaces with a setting in which
% the end-line character is ignored. Then we count it after setting
% it to be a space instead.
\typeout{}%
\typeout{First, we ignore end-of-line characters.}%
\catcode\endlinechar=9\relax%
\scantokens{\cnel@count@spaces{#2}}%
\typeout{}%
\typeout{Then, they are counted as spaces.}%
\catcode\endlinechar=10\relax%
\scantokens{\cnel@count@spaces{#2}}%
% To execute the code, we keep this endline=space setting.
\scantokens{\gdef\cnel@gtmp{#2}}%
\endgroup%
\cnel@gtmp%
}
\newcommand{\cnel@count@spaces}[1]{%
\cnel@count0\relax%
\lowercase{\expandafter\cnel@w\detokenize{. .#1 }\relax%
\typeout{\unexpanded{#1}}%
}%
\typeout{Number of space(s): \the\cnel@count.}%
}
\def\cnel@w.#1.{%
\def\cnel@w@aux##1#1##2\relax{%
\ifempty@nTF{##2}{}{%
\advance \cnel@count by 1\relax%
\cnel@w@aux##2\relax%
}%
}%
\cnel@w@aux%
}
\def\ifempty@nTF#1{%
\expandafter\ifx\expandafter a\detokenize{#1}a%
\expandafter\@firstoftwo%
\else%
\expandafter\@secondoftwo%
\fi%
}
答案2
ConTeXt 提供了\starttexdefinition
...\stoptexdefinition
环境,可以实现这一点。使用它,您可以这样编写命令:
\starttexdefinition myMacro
\invokeX
\invokeY{}
\invokeZ
\stoptexdefinition
我相信LaTeX3也提供了类似的语法。
答案3
对于 LaTeX,使用expl3
包:
\ExplSyntaxOn
\def\myMacro{
\invokeX
\invokeY{}
\invokeZ
}
\ExplSyntaxOff
甚至
\ExplSyntaxOn
\def \myMacro {
\invokeX
\invokeY { }
\invokeZ
}
\ExplSyntaxOff