这是以下问题的后续:在 Lua 中计算字符串的字符数时如何排除 TeX 宏?
感谢@Henri Menke 对该问题的出色回答(如下),我知道如何像\textit{abc}
使用 Lua 一样过滤掉宏。但是,下面的这种方法似乎在这样的环境中失效了\begin{quote}...\end{quote}
。
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
local function rndstring()
local toks = token.scan_toks()
for n, t in ipairs(toks) do
if t.cmdname == "letter" then
-- random number from printable ASCII range
local r = math.random(33, 126)
-- create new token with that character and catcode 12
local letter = token.create(r, 12)
-- replace old token
toks[n] = letter
end
end
token.put_next(toks)
end
local lft = lua.get_functions_table()
lft[#lft + 1] = rndstring
token.set_lua("rndstring", #lft, "global")
\end{luacode}
\begin{document}
\ttfamily
\rndstring{This string works.}
\rndstring{\textit{This string works}}
\rndstring{\begin{quote}This String Does not work\end{quote}}
\end{document}
答案1
这会设置一个布尔标志,并且仅在为真时更改字母。如果看到\begin
或,\end
则该标志设置为假,直到}
看到a,这样环境名称就不会被破坏。
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
local function rndstring()
local toks = token.scan_toks()
local on = true
for n, t in ipairs(toks) do
if t.csname == "begin" or t.csname == "end" then
on = false
end
if not(on) and t.cmdname == "right_brace" then
on = true
end
if on and t.cmdname == "letter" then
-- random number from printable ASCII range
local r = math.random(33, 126)
-- create new token with that character and catcode 12
local letter = token.create(r, 12)
-- replace old token
toks[n] = letter
end
end
token.put_next(toks)
end
local lft = lua.get_functions_table()
lft[#lft + 1] = rndstring
token.set_lua("rndstring", #lft, "global")
\end{luacode}
\begin{document}
\ttfamily
\rndstring{This string works.}
\rndstring{\textit{This string works}}
\rndstring{\begin{quote}This String Does not work\end{quote}}
\end{document}