localload_module="Module:load"localstring_char_module="Module:string/char"localfind=string.findlocalgsub=string.gsublocalmatch=string.matchlocalrequire=requirelocaltonumber=tonumberlocalfunctionu(...)u=require(string_char_module)returnu(...)endlocalentitieslocalfunctionget_entities()entities,get_entities=require(load_module).load_data("Module:data/entities"),nilreturnentitiesendlocalfunctiondecode_entity(hash,x,code)-- "#" isn't included in "[%w\128-\255]", so if no "#" is found then it's a-- a named entity or a false match.ifhash==""thenreturn(entitiesorget_entities())[x..code]end-- Exclude numbers that don't fit the expected format.localcpifx==""thencp=match(code,"^()%d+$")andtonumber(code)elsecp=match(code,"^()%x+$")andtonumber(code,16)end-- Exclude surrogates (U+D800 to U+DFFF) and codepoints that are too high.returncpand(cp<=0xD7FForcp>=0xE000andcp<=0x10FFFF)andu(cp)ornilendreturnfunction(str)-- As an optimisation, only do a full search with gsub() if plain searches-- for "&" and ";" find anything.localamp=find(str,"&",nil,true)-- Search for ";" after the point "&" was found.returnampandfind(str,";",amp+1,true)and-- Non-ASCII characters aren't valid in proper HTML named entities, but-- MediaWiki uses them in some nonstandard aliases (which have also been-- included in [[Module:data/entities]]), so include them anyway.gsub(str,"&(#?)([xX]?)([%w\128-\255]+);",decode_entity)orstrend