我想实现类似于\detokenize
Lua 函数的功能。但有一种情况阻碍了我实现目标。
\directlua{tex.sprint("[" .. token.get_next().csname .. "]")}\par
\directlua{tex.sprint("[" .. token.get_next().csname .. "]")}\UNDEFINED
上面的第一行输出[par]
,其他行输出[]
。token.get_next().csname
用替换token.scan_csname()
没有帮助。如何在 LuaTeX 中获取未定义的控制序列的名称?
答案1
请注意,您不会得到空字符串,因为\UNDEFINED
未定义,而是因为它从未被 TeX 扫描过(因此没有该名称的内部标记)
这个普通的 luatex
\long\def\z#1{%
\directlua{texio.write_nl("[" .. token.scan_csname() .. "]")}#1%
\directlua{texio.write_nl("[" .. token.get_next().csname .. "]")}#1%
}
\z\par
\z\UNDEFINED
\bye
生成日志
[par]
[par]
[UNDEFINED]
[UNDEFINED]
表明只要\UNDEFINED
被 TeX 的#1
参数扫描器看到就足以获得您期望的行为。
答案2
一种可能的方法是使用扩展/执行一些后续标记expand
的功能scan_toks()
,类似于这个答案。
在下面的例子中,
- 函数
f
执行简单操作token.get_next()
(不处理以下标记不在哈希表中的情况) - 函数
g
用于scan_toks(false, true)
扩展输入,并\immediateassignment
结合\futurelet
强制 TeX 对下一个标记进行标记。 - 函数
h
用途协程技巧 (尽管不是使用协同程序,而是使用辅助函数)来调用\futurelet
。\immediateassignment
如果它需要在仅扩展上下文中工作,则可以添加;然而在 o 扩展上下文中它仍然无法工作。
%! TEX program = lualatex
\documentclass{article}
\usepackage{luacode}
\ExplSyntaxOn
\use_none:n {\__unused} % put the token \__unused into the hash table
\cs_new_protected:Npn \__h_aux { \directlua{h_aux()} }
\ExplSyntaxOff
\begin{luacode*}
print("\n\n\n\n")
function f()
print("f: csname =", token.get_next().csname)
end
function g()
token.put_next {
token.create(string.byte "{", 1),
token.create "immediateassignment",
token.create "futurelet",
token.create "__unused",
token.create(string.byte "}", 2),
}
token.scan_toks(false, true)
print("g: csname =", token.get_next().csname)
end
function h()
tex.sprint {
token.create "futurelet",
token.create "__unused",
token.create "__h_aux",
}
end
function h_aux()
print("h: csname =", token.get_next().csname)
end
\end{luacode*}
% normal behavior: tokens never seen before (not in the hash table) results in empty csname
\directlua{f()}\par
\directlua{f()}\undefined
\directlua{f()}\undefineda
\directlua{f()}\undefineda
\directlua{f()}\undefinedb
% use function g instead
\directlua{g()}\par
\directlua{g()}\undefined
\directlua{g()}\undefineda
\directlua{g()}\undefineda
% just checking, undefinedb is still not in the hash table
\directlua{f()}\undefinedb
% use function h instead
\directlua{h()}\par
\directlua{h()}\undefined
\directlua{h()}\undefinedb
\directlua{h()}\undefinedb
\begin{luacode*}
print("\n\n\n\n")
\end{luacode*}
\begin{document}
\end{document}
输出为
f: csname = par
f: csname = undefined
f: csname =
f: csname =
f: csname =
g: csname = par
g: csname = undefined
g: csname = undefineda
g: csname = undefineda
f: csname =
h: csname = par
h: csname = undefined
h: csname = undefinedb
h: csname = undefinedb
您可以看到该函数g()
并h()
正确获取 csname,即\undefineda
和\undefinedb
。