这是对上一个问题由于受到不公正对待,该账户已被关闭。
简要回顾:让\newcommand{\foo}{foo}
.\foo
在文本中像这样
test \foo bar
将省略后面的空格\foo
,结果为test foobar
,而
test {\foo} bar
test {\foo}.
生产test foo bar
,test foo.
这正是我所需要的。
虽然在解析宏之前无法对其进行支撑,但有一种方法可以使空格成为活动字符。
这是解决方案经过埃格尔这很接近我想要的。但是它使用了额外的环境包装器。
我的问题是如何应用相同的技术来创建活动空间,但只在之后一次\foo
?因此,它\foo
需要一个参数,根据空格对其进行解析,并放入#1 foo
文本中,如果存在空格则保留空格。
答案1
这是我能想到的一个解决方案,它只使用纯 TeX。
\def\checkspace{\catcode`\ =12\relax\futurelet\csps\checkspaceA}
\def\checkspaceA{\catcode`\ =10\relax\if\space\csps\ \afterassignment\ignorespaces\expandafter\let\expandafter\csps\fi}
\def\foo{foo\checkspace}
test \foo bar
test foo bar
test \foo.
\bye
这个想法是这样的:\checkspace
首先创建空格其他这样它们就不会被跳过并且可以被'd。然后我们使用\futurelet
来检查下一个标记。 使空格再次成为空格标记,并且如果我们检查的标记是空格,则插入 a。\checkspaceA
\futurelet
\checkspaceA
\
条件中的其余代码的目的\checkspaceA
是确保 if\checkspace
后面跟着多个空格,第一个空格后面的所有空格都将被忽略。首先,我将解释这个问题(就我的理解而言),以便更好地解释我的解决方案。
如果我们删除此代码\checkspaceA
并执行以下测试:
\def\checkspaceA{\catcode`\ =10\relax\if\space\csps\ \fi}
test \foo bar
然后我们会得到test foo
一个空格,然后是一个其他空格字符(看起来像 cmr 中的斜线),然后bar
。问题是,一旦我们\futurelet\csps\checkspaceA
在 中执行此操作\checkspace
,后面的标记\foo
就会被标记成其他空格标记,并留在流中,这就是创建奇怪的破折号字符的原因。
所以我们可以稍微修改一下代码来解决这个问题:
\def\checkspaceA{\catcode`\ =10\relax\if\space\csps\ \expandafter\let\expandafter\csps\fi}
test \foo bar
但现在的问题是,由于后面有两个空格\foo
,第一个空格被正确地转换为\
by \checkspaceA
。但下一个空格标记实际上跟在其他标记,因此不会被忽略。\afterassignment\ignorespaces
在之前执行\let
可确保它被忽略。
此解决方案不适用于 catcode 为 10 的任何字符,并且设置宏以使其适用于其他字符需要更改多个字符的 catcode 并嵌套\if
。
总的来说,我真没觉得这些宏有什么用处,我觉得在宏后面加上一个空组可能更简单。这样做几乎肯定不会遇到奇怪的意外副作用。
我不能 100% 确定我的宏是否一直有效,如果它们有问题,请随时告诉我,我很乐意尝试修复它们。