无法从 ConTeXt Lua 生成的 METAPOST 代码打印花括号(带有最少的示例)

无法从 ConTeXt Lua 生成的 METAPOST 代码打印花括号(带有最少的示例)

[问题也在 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。

相关内容