这个问题似乎出现过几次,但我无法找到这个一般性问题的答案:如何保护 Lua 中的任意字符串以确保其字符被打印。
换句话说,给定.lua
文件中的某些代码:
local i_can_be_anything = '&\\%*_'
context(i_can_be_anything)
由于多种原因,这都会失败,因为当 ConTeXt 将字符推送到 TeX 编译器时,这些字符在 TeX 中具有特殊含义。
对我来说,最明显的选择是在 Lua 中转换字符串,使其包含适当的转义或替换,可以传递给 TeX 以实现所需的结果,在这种情况下将是这样的:
\&\textbackslash{}\%\&\_
我相信人们所寻找的替换的完整列表将是这样的(这是我编写的一些 Python 代码):
tex_replacements = [
(u'{', ur'\{'),
(u'}', ur'\}'),
(u'[', ur'{[}'),
(u']', ur'{]}'),
(u'\\', ur'\textbackslash{}'),
(u'$', ur'\$'),
(u'%', ur'\%'),
(u'&', ur'\&'),
(u'#', ur'\#'),
(u'_', ur'\_'),
(u'~', ur'\textasciitilde{}'),
(u'^', ur'\textasciicircum{}'),
]
tex_mapping = {ord(char):rep for char, rep in tex_replacements}
def escape(s):
return unicode(s).translate(tex_mapping)
Lua 或 LuaTeX 中是否没有函数来实现这组替换(或其他)以便可以打印任意字符串?
按照上面的方法对字符进行简单的迭代和替换tex_replacements
就可以解决这个问题,但我希望有人已经写出了解决这个问题的方法。
编辑
值得注意的是,@phg 提出了一个可行的解决方案,即将 catcodes 更改为 vrbcatcode(即\verbatim
或context.sprint(catcodes.numbers.vrbcatcodes, i_can_be_anything)
)。这确实执行了所需的转义,但是似乎有严重的断线问题这使得它基本上无法使用。
答案1
此答案基于 Hans Hagen 的一封电子邮件。实现所需输出的一种方法是使用格式化程序。 例如:
\starttext
\startluacode
local text='&\%*_'
context("%!tex!", text)
\stopluacode
\stoptext
是%!tex!
格式化程序的插件,tex
是预定义格式化程序之一。其他预定义格式化程序是lua
和xml
(分别用于转义 Lua 和 XML 的字符串)。
上述代码相当于
context(string.formatters["%!tex!"](text))
这相当于相当低级的
context(lpeg.match(lpeg.patterns.texescape,text))
lua
和xml
格式化程序的相应 lpeg 模式为lpeg.patterns.luaescape
和lpeg.patterns.xmlescape
。它们在 中定义util-str.lua
为:
patterns.xmlescape = Cs((P("<")/"<" + P(">")/">" + P("&")/"&" + P('"')/""" + P(1))^0)
patterns.texescape = Cs((C(S("#$%\\{}"))/"\\%1" + P(1))^0)
patterns.luaescape = Cs(((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n"')^0) -- maybe also \0
patterns.luaquoted = Cs(Cc('"') * ((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n"')^0 * Cc('"'))
luaquoted
核心中未使用该模式。
答案2
我在这里总结一下评论,但要点是:
@phg 建议可以使用猫代码。有 catcode verbatim
,但它有换行问题。
另一种选择是 catcode,尽管没有记录,但似乎更可取(即没有包装问题的转义)\notcatcodes
。
可以在 Lua 中使用它来转义任何字符串,如下所示:
context.sprint(catcodes.numbers.notcatcodes, str)
-- or --
context.pushcatcodetable()
context.setcatcodetable(catcodes.numbers.vrbcatcodes)
context(str)
context.popcatcodetable()