使用 ConTeXt 转义从 Lua 打印的字符串

使用 ConTeXt 转义从 Lua 打印的字符串

这个问题似乎出现过几次,但我无法找到这个一般性问题的答案:如何保护 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(即\verbatimcontext.sprint(catcodes.numbers.vrbcatcodes, i_can_be_anything))。这确实执行了所需的转义,但是似乎有严重的断线问题这使得它基本上无法使用。

答案1

此答案基于 Hans Hagen 的一封电子邮件。实现所需输出的一种方法是使用格式化程序。 例如:

\starttext
\startluacode
  local text='&\%*_'
  context("%!tex!", text)
\stopluacode
\stoptext

%!tex!格式化程序的插件,tex是预定义格式化程序之一。其他预定义格式化程序是luaxml(分别用于转义 Lua 和 XML 的字符串)。

上述代码相当于

context(string.formatters["%!tex!"](text))

这相当于相当低级的

context(lpeg.match(lpeg.patterns.texescape,text))

luaxml格式化程序的相应 lpeg 模式为lpeg.patterns.luaescapelpeg.patterns.xmlescape。它们在 中定义util-str.lua为:

patterns.xmlescape = Cs((P("<")/"&lt;" + P(">")/"&gt;" + P("&")/"&amp;" + P('"')/"&quot;" + 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()

相关内容