使用Lua取消转义数字XML实体

什么是将数字HTML/XML实体转义的良好实现,例如
并将其替换为ASCII等价物?

表示为单元测试:

local orig = "It's the "end" &ok;
"
local fixd = unescape(orig) -- Implement this
assert( fixd == "It's the \"end\" &ok;\n" )
点赞
用户405017
用户405017

以下是一个简单的实现,可以处理核心名称为 XML 的实体:

function unescape(str)
  str = string.gsub( str, '&lt;', '<' )
  str = string.gsub( str, '&gt;', '>' )
  str = string.gsub( str, '&quot;', '"' )
  str = string.gsub( str, '&apos;', "'" )
  str = string.gsub( str, '&#(%d+);', function(n) return string.char(n) end )
  str = string.gsub( str, '&#x(%d+);', function(n) return string.char(tonumber(n,16)) end )
  str = string.gsub( str, '&amp;', '&' ) -- 确保在所有其他情况之后执行此操作
  return str
end

print(unescape("&#34;Hello&quot; &apos;World&#39;")) --> "Hello" 'World'

但是,请注意,对于一种病态情况,它会失败:以数字和符号 amp; 开头的实体:

print(unescape("Ampersand entity is &#38;amp;")) --> Ampersand entity is &
-- 实际结果应为                                      Ampersand entity is &amp;

我们可以通过一次处理所有实体来修复这个边缘情况,但是代码变得更加丑陋:

function unescape(str)
  local map={ ["lt"]="<", ["gt"]=">", ["amp"]="&", ["quot"]='"', ["apos"]="'" }
  str = string.gsub( str, '(&(#?x?)([%d%a]+);)', function(orig,n,s)
    return (n=='' and map[s])
           or (n=="#x" and tonumber(s,16)) and string.char(tonumber(s,16))
           or (n=="#" and tonumber(s)) and string.char(s)
           or orig
  end )
  return str
end

print(unescape("Ampersand entity is &#38;amp;")) --> Ampersand entity is &amp;

最后,我们可以展开它,以获得更高的速度:

local gsub, char = string.gsub, string.char
local entityMap  = {["lt"]="<",["gt"]=">",["amp"]="&",["quot"]='"',["apos"]="'"}
local entitySwap = function(orig,n,s)
  return (n=='' and entityMap[s])
         or (n=="#" and tonumber(s)) and string.char(s)
         or (n=="#x" and tonumber(s,16)) and string.char(tonumber(s,16))
         or orig
end
function unescape(str)
  return (gsub( str, '(&(#?x?)([%d%a]+);)', entitySwap ))
end
2013-02-15 17:06:45
用户1599009
用户1599009

现在有一个 htmlEntities-for-lua 模块可以通过 LuaRocks 使用,您应该使用它。它在代码中仅使用了 3 个 string.gsub 迭代,因此它更快且更完整。

htmlEntities = require('htmlEntities')

print(htmlEntities.decode(yourString))

或者将其用作您当前功能的替代品:

myUnescape = require('htmlEntities').decode
2019-03-11 22:26:44