编者注:这个问题经过了重大修改,它可能反映也可能不反映 OP 的初衷。如果没有反映,OP 可能希望将其回滚并澄清问题/提供适当的 MWE。
这个问题是为了学术目的,而不是为了实际应用。
您能否在传统 TeX 中编写一个可扩展的宏以便 产生结果 ? (替换文本的最后一项是第 1 类不平衡的左花括号。)\macro{⟨argument⟩}
{⟨argument⟩}{
例如,
\macro {123{4 5{6}}789}
经过一些扩展步骤后,应该会扩展为
{123{4 5{6}}789}{
答案应该只使用可扩展操作(在 expl3 项中,在 f 型扩展中起作用);并且\expanded
在传统的 TeX 中不可用。
任何(非外部、非\notexpanded
)标记都可能出现在参数中,包括一些内部标记,例如冻结的字体选择标记。
答案1
在你的问题中你说:
(最后一件事替换文本是第 1 类不平衡左花括号。)
当引用宏时,短语“替换文本”通常表示属于该宏定义的替换文本。
大卫·卡莱尔已经在评论宏定义的替换文本不能包含不平衡/不匹配的括号/类别 1 或 2 的显式字符标记。
TeXbook,第 20 章:定义(也称为宏),说:
\def
⟨控制序列⟩⟨参数文本⟩{
⟨替换文本⟩}
TeXbook,第 24 章:垂直模式摘要,介绍了 Backus/Naur 表示法中的 TeX 语法。在该章中,您可以找到:
⟨定义⟩→⟨def⟩⟨控制序列⟩⟨定义文本⟩
⟨def⟩→\def
|\gdef
|\edef
|\xdef
⟨定义文本⟩→⟨参数文本⟩⟨左括号⟩⟨平衡文本⟩⟨右括号⟩
[...]
所有出现的⟨左括号⟩和⟨右括号⟩内的代币⟨平衡文本⟩必须像括号一样正确嵌套。
因此,无论如何,宏定义的替换文本都是由以下部分组成的:⟨平衡文本⟩其中大括号是平衡的/正确嵌套的。
因此,我认为问题不在于宏定义的替换文本包含不匹配/不平衡的括号,而在于宏
- 其定义的替换文本不包含不匹配/不平衡的括号
- 它接受一个未限定的参数,并且可以用于启动扩展级联,在经过已知数量的扩展步骤之后,将产生1 个形成嵌套在花括号中的参数的标记,并且该标记后面跟着一个与结束花括号不匹配/不平衡的开始花括号。
问题 1:
如果存在括号内的参数,应如何\macro
处理?
问题2:
的参数没有被括号括起来的情况该如何\macro
处理?
如果
- 问题 1 的答案是“
\macro
可以去掉 参数周围的括号,而可以添加另一对括号(可能产生不同字符代码的括号)”并且 - 问题 2 的答案是“结果,参数无论如何都应被括号括起来”,并且
- 问题与传统 TeX 无关2、
然后你就可以提取要点Skillmon 对“以完全可靠的方式访问标记列表中的第一个项目(可扩展)”问题的回答,即结合\expanded
和\unexpanded
。
以下\macro
是触发两个扩展步骤/两次“命中”后的结果\expandafter
。
1问题回答者的观点是“收益”这个短语没有非常精确地描述要求。
2短语“问题与传统 TeX 无关“ 加粗强调答题者知道这个答案并没有真正回答问题,因为这个答案偏离了问题给出的要求/条件。
\long\def\macro#1{\expanded{\unexpanded{{#1}}\expandafter}\expandafter{\iffalse}\fi}
\long\def\processtwoargs#1#2{%
\message{^^J\unexpanded{argument 1: (#1) argument 2: (#2)}}%
}%
% Tests:
\expandafter\expandafter\expandafter\processtwoargs\macro{first}second}
\expandafter\expandafter\expandafter\processtwoargs\macro{123{4 5{6}}789}second}
\expandafter\expandafter\expandafter\processtwoargs\macro{###}###}
\message{^^JJust make sure there is no confusion about hash-doubling:}
\message{^^J\unexpanded{argument 1: (###) argument 2: (###)}}
\csname bye\endcsname
\csname stop\endcsname
\endinput
终端上的消息:
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdftex)
restricted \write18 enabled.
entering extended mode
(./test.tex
argument 1: (first) argument 2: (second)
argument 1: (123{4 5{6}}789) argument 2: (second)
argument 1: (######) argument 2: (######)
Just make sure there is no confusion about hash-doubling:
argument 1: (######) argument 2: (######) )
No pages of output.
Transcript written on test.log.
答案2
我会做出同样的假设Ulrich Diez 的回答,除了\expanded
/\unexpanded
部分。
据我所知,这个解决方案可以毫无问题地移植到 Knuth TeX。
为了简单起见,我稍微改变了一下计划:
- 首先,将 token 列表“序列化”为 N 类型 token 列表,具体原理如下
principle:
a token X is serialized to two N-type tokens AB such that r-expansion of AB results in X, and A ≠ \relax
actual encoding:
begin-group character X is encoded to \bgroup_handler ⟨X in catcode other⟩,
end-group character X is encoded to \egroup_handler ⟨X in catcode other⟩,
blank space is encoded to \space_handler ⟨any N-type token⟩
anything else is encoded to \exp_end: ⟨that token⟩
然后附加单个 begin-group 字符的序列化,
然后反序列化整个事物。
就是这样。我有一些代码,但不是某种可以直接在 Knuth-TeX 上运行的形式。如果你坚持,请继续阅读。
它需要一个工作\char_generate:nn
函数,可以通过为所有字符代码准备所有 256×2 个字符来实现。
实际的代码建立在 Ulrich Diez 的代码之上,用于获取{
和 的字符串表示形式}
https://tex.stackexchange.com/a/628363/250119,稍作修改,返回 catcode other 中的空格而不是空格。
新部件的详细信息位于我的存储库中的某个文件中https://github.com/user202729/TeXlib/blob/main/test_imperative.tex#L644-L773。它需要编译该 repo 中的一些其他文件。
附注:在该代码中,“⟨token list⟩ 的 r 扩展”意味着“'\romannumeral ⟨token list⟩' 的 o 扩展”。
目前,如果您想运行代码,您需要下载整个 repo 并使用 LuaLaTeX 运行文件来“编译”代码。这不是很容易。
但是原理是存在的,并且它在我的测试中有效。(通过序列化/反序列化令牌列表并观察输出,并通过实现\weirdfirstarg
提取第一个参数并查看它是否正常工作)
不幸的是,目前时间复杂度高于承诺的 O(n² log n),其中 n 是令牌的数量。