背景
希望对任意字符串执行文本替换。在代码片段中,值#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