[问题也在 ConTeXt 邮件列表中提出,我将在另一个邮件列表中发布解决方案] 以下最小示例说明了我的问题。 我需要从 METAPOST(使用 作为标签)排版通用字符串(使用 lua 从 XML 文件读取)。textext()
使用 ConTeXt 运行以下文件会产生一个结果,说明从 Lua 转到 METAPOST 时花括号会丢失,但转义它们不起作用。 我试图避免使用\type{}
因为最后的标签需要是一个小段落,所以在排版期间使用 TeX \vbox
。
如果这不可能(我猜可能是因为 TeX 的工作方式),我需要将 XML 中的文本拆分为空格分隔的元素,然后将每个元素放入一个段落中,type{}
然后将它们合并为一个段落。这会很复杂且混乱。
\usemodule[scite]
\setupxml
[entities=yes]
\startluacode
function warn( ... )
texio.write_nl("-----> " .. string.format(...))
end
local function mpLabelString( xmlLabelString)
-- Returns a string where each " is replaced by a METAPOST compatible result, except for outer double quotes"
rep = {
[1] = { "\"", "\"&ditto&\"" },
-- DOESN'T WORK: [2] = { "\\", "\\\\" },
}
local tmpString = string.formatters( "%!tex!", xmlLabelString)
warn( "STRING.FORMAT XML \"%s\"", xmlLabelString)
warn( "STRING.FORMAT TeX-ed \"%s\"", tmpString)
warn( "STRING.FORMAT Replaced \"%s\"", lpeg.replacer(rep):match(tmpString))
return lpeg.replacer(rep):match(tmpString)
end
function warnAndConTeXt( ...)
warn( ...)
context( ...)
end
function moduledata.test( filename)
local labelString
context( "The string to typeset is:\\par\\type-{Label} \"a\" [Text]!-")
context( "\\par The attempts are:")
context( "\\par1. \\type-Label Text-")
context( "\\par2. \\type-Label [Text]!-")
context( "\\par3. \\type-Label \"a\" [Text]!-")
context( "\\par4. \\type-{Label} [Text]!-")
context( "\\par5. \\type-{Label} \"a\" [Text]!-")
context.startMPpage { instance = "doublefun" }
context( "picture pic;")
labelString = "1. Label Text OK"
warnAndConTeXt( "pic := Foo( 0, 0, 150, 50, \"%s\");", mpLabelString( labelString))
labelString = "2. Label [Text]! OK"
warnAndConTeXt( "pic := Foo( 0, -75, 150, 50, \"%s\");", mpLabelString( labelString))
labelString = "3. Label \"a\" [Text]! OK"
warnAndConTeXt( "pic := Foo( 0, -150, 150, 50, \"%s\");", mpLabelString( labelString))
labelString = "4. {Label} [Text]! MISSING curly braces"
warnAndConTeXt( "pic := Foo( 0, -225, 150, 50, \"%s\");", mpLabelString( labelString))
labelString = "5. {Label} \"a\" [Text]! MISSING curly braces"
warnAndConTeXt( "pic := Foo( 0, -300, 150, 50, \"%s\");", mpLabelString( labelString))
context( "drawdot (0,0) withpen pencircle scaled 4 withcolor red;")
context.stopMPpage()
end
\stopluacode
\usemodule[article-basic]
%\enabletrackers[metapost.tracingall,metapost.lua,metapost.runs,metapost.textexts,metapost.scrintersectionPoints,metapost.runs,metapost.graphics,metapost.terminal]
\starttext
\definefontfamily[mainface][rm][Optima]
\setupbodyfont[mainface,10pt]
\startMPinclusions[+]{doublefun}
\stopMPinclusions
\startMPdefinitions{doublefun}
vardef makeTeXLabel( expr w, h, name) =
show "NAME makeTeXLabel:", name;
save p; picture p ;
save s; string s;
s := "\framed{" & name & "}"; % Curly braces will be missing. I need this to work.
% s := "\type-" & name & "-"; % Curly braces are displayed, but this must become a vbox in the end, so can't use it
show "SCAN:", s;
p := textext( s);
p
enddef;
vardef Foo( expr xpos, ypos, width, height, str) =
show "NAME Foo:", str; % Backslashes are already gone here
save pic; picture pic;
pic := makeTeXLabel( width, height, str) shifted (xpos, ypos);
draw pic;
pic
enddef;
\stopMPdefinitions
\ctxlua{moduledata.test("Whatever")}
\typefile[option=TEX]{filenameofthisfile.tex}
\stoptext
答案1
您的“最小”示例相当长,所以我希望我理解正确。因此,您要做的就是获取一个 Lua 字符串,将其通过 TeX 传递到 MetaPost,然后再次将其传递到 TeX 以排版为标签。
就我所知,您的代码中存在一个问题,那就是您遗漏了最后一步。您假设 MetaPost 会排版文本,但事实并非如此。因此,除了转义所有字符外,"
您还必须转义所有特殊的 TeX 字符。幸运的是,有一个内置函数可以实现这一点context.escape
。
\starttext
\startluacode
local function MPescape(str)
str = context.escape(str)
str = str:gsub("\"", "\" & ditto & \"")
return str
end
local labelString = "5. $ ^ _ % {Label} \"a\" [Text]!"
context.startMPpage()
context.verbatim("draw textext(\"%s\");", MPescape(labelString))
context.stopMPpage()
\stopluacode
\stoptext
答案2
Taco Hoekwater 告诉我一个更好的方法。我现在正在使用以下函数:
function doubleQuotableEscapedConTeXtString( str)
warn( "STRING.ESCAPED in: \"%s\"", str)
warn( "STRING.CONTEXTESCAPED: \"%s\"", context.escape(str))
local rep = {
[1] = { '{', '{\\textbraceleft}' },
[2] = { '}', '{\\textbraceright}' },
[3] = { '#', '{\\texthash}' },
[4] = { '$', '{\\textdollar}' },
[5] = { '&', '{\\textampersand}' },
[6] = { '%', '{\\textpercent}' },
[7] = { '\\','{\\textbackslash}' },
[8] = { '|', '{\\textbar}' },
[9] = { '_', '{\\textunderscore}' },
[10] = { '~', '{\\textasciitilde}' },
[11] = { '^', '{\\textasciicircum}' },
[12] = { '"', "\"&ditto&\"" },
}
warn( "STRING.ESCAPED out: \"%s\"", lpeg.replacer(rep):match(str))
return lpeg.replacer(rep):match(str)
end
(警告仅用于调试)。这样做的好处是我没有verbatim
在任何地方使用,而且它非常强大。
-----> STRING.ESCAPED in: "5. {Label} \DIR "a" [Text]!"
-----> STRING.CONTEXTESCAPED: "5. \{Label\} \\DIR "a" [Text]!"
-----> STRING.ESCAPED out: "5. {\textbraceleft}Label{\textbraceright} {\textbackslash}DIR "&ditto&"a"&ditto&" [Text]!"
我实际上可以用 TeX 命令替换“字符”中的 ditto,从而完全摆脱 ditto。