背景

背景

背景

希望对任意字符串执行文本替换。在代码片段中,值#a.m. #p.m.value 来自文档。更具体地说,输入是从 Markdown 生成的 XML 文档。XML 文档类似于:

<p>See <a class="href" data-type="tbl" href="#ref"/> for details.</p>

事实证明这#ref是有问题的。

系统

ConTeXt 版本:2023.09.26 18:19

代码

显示问题的最小示例:

\startluacode
userdata = userdata or {}

userdata.TextReplacements = {}

local function TextReplacement( text )
  text = string.gsub( text, "#", "\\#" )
  local replaced = lpeg.replacer( userdata.TextReplacements ):match( text )
  context( replaced )
end

interfaces.implement {
  name      = "TextReplacement",
  arguments = { "string" },
  public    = true,
  actions   = TextReplacement,
}
\stopluacode

\startluacode
userdata = userdata or {}

userdata.TextReplacements = {
  [1] = { "a.m.", "\\cap{am}" },
  [2] = { "p.m.", "\\cap{pm}" },
}
\stopluacode

\starttext
  \TextReplacement{#a.m. #p.m.}
\stoptext

细节

另外一个细节是,该#ref值正在从锚点的链接读入 ConTeXt 并进行如下查找:

\startxmlsetups xml:xhtml
  \xmlsetsetup{\xmldocument}{a[@class='href']}{xml:anchorhref}
\stopxmlsetups

\startxmlsetups xml:anchorhref
  Xref = \xmlatt{#1}{data-type}-\xmlatt{#1}{href}
\stopxmlsetups

anchorhref从设置内部执行,xml:p如下所示:

\startxmlsetups xml:p
  \xmldoifnotselfempty{#1}{%
    \ignorespaces
    \expandafter\TextReplacement{\xmlflush{#1}}
    \removeunwantedspaces
  }
  \par
\stopxmlsetups

由于符号的原因,该调用\TextReplacement不起作用#

问题

维基百科建议使用lpeg.replacer( ... ):match( ... ),但这会产生编译错误。

通过添加对的调用string.gsub,编译错误消失,但输出会产生双重井号:

##AM ##PM

问题

如何转义哈希符号和任何可能导致字符串替换失败的其他符号,以便不输出双重哈希?

有关的

答案1

我在阅读这个问题的时候碰巧联系了汉斯。他首先提到

\starttext
   \catcode`#=11
   \TextReplacement{#a.m. #p.m.}
\stoptext

但这可能会在加载模块等时出现问题。然后他解释说,在 lmtx 中我们可以使用

text = string.gsub( text, "#", "#H" )

#H是一个哈希转义。

\starttext
   #Ha.m. #Hp.m.
\stoptext

给予

上午下午

您可以在以下网址阅读有关此内容以及更多精彩新事物的信息低级宏.pdf在你的发行版中。

然后他还提到,每次编译替换器效率不高(你可能没有在网络服务上运行,所以这可能不是问题),所以你最好做类似的事情

local replacer = lpeg.replacer( userdata.TextReplacements )

local function TextReplacement( text )
   text = string.gsub( text, "#", "#H" )
   context(replacer:match(text))
end

我不想因此而获得任何名誉,所以我把它做成了社区维基。

答案2

这样就不会进行双重替换?

实际上并没有发生双重替换;就 Lua 处理器而言,哈希符号只是出现了两次。以下文档

\startluacode
    interfaces.implement {
        name      = "test",
        arguments = { "string" },
        public    = true,
        actions   = function(str)
            print("START OUTPUT")
            print(str)
            print("STOP OUTPUT")
        end
    }
\stopluacode

\test{#a}

输出如下:

START OUTPUT
##a
STOP OUTPUT

所以而不是

text:gsub("#", ...)

你需要写

text:gsub("##", ...)

如何转义井号和其他符号

有很多选择:

\starttext
\startluacode
    str = "#"

    -- Naïve solution, does not work
    -- context(str)
    -- context.par()

    -- Output in verbatim
    context.verbatim(str)
    context.par()

    -- Backslash escape
    context(str:gsub(str, "\\#"))
    context.par()

    -- \char escape
    context(str:gsub(str, "\\char`\\#"))
    context.par()

    -- ConTeXt escape command
    context(str:gsub(str, "\\letterhash"))
    context.par()

    -- Escape formatter string
    context("%s %!tex! %02X", "test", str, 10)
    context.par()

    -- Manually run the same function
    context(lpeg.match(lpeg.patterns.texescape, str))
    context.par()
\stopluacode
\stoptext

示例输出

相关内容