2013-02-15 48 views
2

對於消除數字HTML/XML實體的好實現
和替換它們與ASCII等效?帶有Lua的Unescape數字XML實體

表示爲一個單元測試:

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

回答

5

這裏有一個簡單的實現,也負責處理核心命名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;', '&') -- Be sure to do this after all others 
    return str 
end 

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

但是請注意,這個失敗的一種病理性的情況:一個數字&符實體後跟文字amp;

print(unescape("Ampersand entity is &#38;amp;")) --> Ampersand entity is & 
-- The result should actually be      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 
+0

應檢查'n ==可 「」'的'entityMap'情況下(或者你可能會不小心匹配'' mp;) – daurnimator 2016-11-10 15:27:49

2

對於少數程序員在下載法語html內容時可能需要避免重音,這裏是上述功能的更廣泛的版本。

local function unescape(str) 
    str = string.gsub(str, '&nbsp;', ' ') 
    str = string.gsub(str, '&iexcl;', '¡') 
    str = string.gsub(str, '&cent;', '¢') 
    str = string.gsub(str, '&pound;', '£') 
    str = string.gsub(str, '&curren;', '¤') 
    str = string.gsub(str, '&yen;', '¥') 
    str = string.gsub(str, '&brvbar;', '¦') 
    str = string.gsub(str, '&sect;', '§') 
    str = string.gsub(str, '&uml;', '¨') 
    str = string.gsub(str, '&copy;', '©') 
    str = string.gsub(str, '&ordf;', 'ª') 
    str = string.gsub(str, '&laquo;', '«') 
    str = string.gsub(str, '&not;', '¬') 
    str = string.gsub(str, '&shy;', '­') 
    str = string.gsub(str, '&reg;', '®') 
    str = string.gsub(str, '&macr;', '¯') 
    str = string.gsub(str, '&deg;', '°') 
    str = string.gsub(str, '&plusmn;', '±') 
    str = string.gsub(str, '&sup2;', '²') 
    str = string.gsub(str, '&sup3;', '³') 
    str = string.gsub(str, '&acute;', '´') 
    str = string.gsub(str, '&micro;', 'µ') 
    str = string.gsub(str, '&para;', '¶') 
    str = string.gsub(str, '&middot;', '·') 
    str = string.gsub(str, '&cedil;', '¸') 
    str = string.gsub(str, '&sup1;', '¹') 
    str = string.gsub(str, '&ordm;', 'º') 
    str = string.gsub(str, '&raquo;', '»') 
    str = string.gsub(str, '&frac14;', '¼') 
    str = string.gsub(str, '&frac12;', '½') 
    str = string.gsub(str, '&frac34;', '¾') 
    str = string.gsub(str, '&iquest;', '¿') 
    str = string.gsub(str, '&Agrave;', 'À') 
    str = string.gsub(str, '&Aacute;', 'Á') 
    str = string.gsub(str, '&Acirc;', 'Â') 
    str = string.gsub(str, '&Atilde;', 'Ã') 
    str = string.gsub(str, '&Auml;', 'Ä') 
    str = string.gsub(str, '&Aring;', 'Å') 
    str = string.gsub(str, '&AElig;', 'Æ') 
    str = string.gsub(str, '&Ccedil;', 'Ç') 
    str = string.gsub(str, '&Egrave;', 'È') 
    str = string.gsub(str, '&Eacute;', 'É') 
    str = string.gsub(str, '&Ecirc;', 'Ê') 
    str = string.gsub(str, '&Euml;', 'Ë') 
    str = string.gsub(str, '&Igrave;', 'Ì') 
    str = string.gsub(str, '&Iacute;', 'Í') 
    str = string.gsub(str, '&Icirc;', 'Î') 
    str = string.gsub(str, '&Iuml;', 'Ï') 
    str = string.gsub(str, '&ETH;', 'Ð') 
    str = string.gsub(str, '&Ntilde;', 'Ñ') 
    str = string.gsub(str, '&Ograve;', 'Ò') 
    str = string.gsub(str, '&Oacute;', 'Ó') 
    str = string.gsub(str, '&Ocirc;', 'Ô') 
    str = string.gsub(str, '&Otilde;', 'Õ') 
    str = string.gsub(str, '&Ouml;', 'Ö') 
    str = string.gsub(str, '&times;', '×') 
    str = string.gsub(str, '&Oslash;', 'Ø') 
    str = string.gsub(str, '&Ugrave;', 'Ù') 
    str = string.gsub(str, '&Uacute;', 'Ú') 
    str = string.gsub(str, '&Ucirc;', 'Û') 
    str = string.gsub(str, '&Uuml;', 'Ü') 
    str = string.gsub(str, '&Yacute;', 'Ý') 
    str = string.gsub(str, '&THORN;', 'Þ') 
    str = string.gsub(str, '&szlig;', 'ß') 
    str = string.gsub(str, '&agrave;', 'à') 
    str = string.gsub(str, '&aacute;', 'á') 
    str = string.gsub(str, '&acirc;', 'â') 
    str = string.gsub(str, '&atilde;', 'ã') 
    str = string.gsub(str, '&auml;', 'ä') 
    str = string.gsub(str, '&aring;', 'å') 
    str = string.gsub(str, '&aelig;', 'æ') 
    str = string.gsub(str, '&ccedil;', 'ç') 
    str = string.gsub(str, '&egrave;', 'è') 
    str = string.gsub(str, '&eacute;', 'é') 
    str = string.gsub(str, '&ecirc;', 'ê') 
    str = string.gsub(str, '&euml;', 'ë') 
    str = string.gsub(str, '&igrave;', 'ì') 
    str = string.gsub(str, '&iacute;', 'í') 
    str = string.gsub(str, '&icirc;', 'î') 
    str = string.gsub(str, '&iuml;', 'ï') 
    str = string.gsub(str, '&eth;', 'ð') 
    str = string.gsub(str, '&ntilde;', 'ñ') 
    str = string.gsub(str, '&ograve;', 'ò') 
    str = string.gsub(str, '&oacute;', 'ó') 
    str = string.gsub(str, '&ocirc;', 'ô') 
    str = string.gsub(str, '&otilde;', 'õ') 
    str = string.gsub(str, '&ouml;', 'ö') 
    str = string.gsub(str, '&divide;', '÷') 
    str = string.gsub(str, '&oslash;', 'ø') 
    str = string.gsub(str, '&ugrave;', 'ù') 
    str = string.gsub(str, '&uacute;', 'ú') 
    str = string.gsub(str, '&ucirc;', 'û') 
    str = string.gsub(str, '&uuml;', 'ü') 
    str = string.gsub(str, '&yacute;', 'ý') 
    str = string.gsub(str, '&thorn;', 'þ') 
    str = string.gsub(str, '&yuml;', 'ÿ') 
    str = string.gsub(str, '&euro;', '€') 
    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;', '&') -- Be sure to do this after all others 
    return str 
end 
+0

注意,技術上這個名單是適當的HTML,不是XML。但是謝謝你的加入! – Phrogz 2016-07-19 13:43:18

+0

'κ'意味着'к'(俄語字母),但它失敗 – val 2017-06-09 17:10:09