Jump to content
Wikipedia The Free Encyclopedia

Module:Excerpt

From Wikipedia, the free encyclopedia
Module documentation[view] [edit] [history] [purge]
This module is rated as beta. It is considered ready for widespread use, but as it is still relatively new, it should be applied with some caution to ensure results are as expected.
Page template-protected This module is currently protected from editing.
See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected.
Warning This Lua module is used on approximately 13,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them.
This module depends on the following other modules:

This module implements Template:Excerpt.

Portals

Portals use a previous version of this module:

The above documentation is transcluded from Module:Excerpt/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit) pages.
Subpages of this module.

 -- Module:Excerpt implements the Excerpt template
 -- Documentation and master version: https://en.wikipedia.org/wiki/Module:Excerpt
 -- Authors: User:Sophivorus, User:Certes, User:Aidan9382 & others
 -- License: CC-BY-SA-3.0

 localparser=require('Module:WikitextParser')
 localyesno=require('Module:Yesno')

 localok,config=pcall(require,'Module:Excerpt/config')
 ifnotokthenconfig={}end

 localExcerpt={}

 -- Main entry point for templates
 functionExcerpt.main(frame)

 -- Make sure the requested page exists and get the wikitext
 localpage=Excerpt.getArg(1)
 ifnotpageorpage=='{{{1}}}'thenreturnExcerpt.getError('no-page')end
 localtitle=mw.title.new(page)
 ifnottitlethenreturnExcerpt.getError('invalid-title',page)end
 localfragment=title.fragment-- save for later
 iftitle.isRedirectthen
 title=title.redirectTarget
 iffragment==""then
 fragment=title.fragment-- page merge potential	
 end
 end
 ifnottitle.existsthenreturnExcerpt.getError('page-not-found',page)end
 page=title.prefixedText
 localwikitext=title:getContent()

 -- Get the template params and process them
 localparams={
 hat=yesno(Excerpt.getArg('hat',true)),
 this=Excerpt.getArg('this'),
 only=Excerpt.getArg('only'),
 files=Excerpt.getArg('files',Excerpt.getArg('file')),
 lists=Excerpt.getArg('lists',Excerpt.getArg('list')),
 tables=Excerpt.getArg('tables',Excerpt.getArg('table')),
 templates=Excerpt.getArg('templates',Excerpt.getArg('template')),
 paragraphs=Excerpt.getArg('paragraphs',Excerpt.getArg('paragraph')),
 references=yesno(Excerpt.getArg('references',true)),
 subsections=yesno(Excerpt.getArg('subsections',false)),
 links=yesno(Excerpt.getArg('links',true)),
 bold=yesno(Excerpt.getArg('bold',false)),
 briefDates=yesno(Excerpt.getArg('briefdates',false)),
 inline=yesno(Excerpt.getArg('inline')),
 quote=yesno(Excerpt.getArg('quote')),
 more=yesno(Excerpt.getArg('more')),
 class=Excerpt.getArg('class'),
 track=yesno(Excerpt.getArg('track',true)),
 displayTitle=Excerpt.getArg('displaytitle',page),
 }

 -- Make sure the requested section exists and get the excerpt
 localexcerpt
 localsection=Excerpt.getArg(2,fragment)
 section=mw.text.trim(section)
 ifsection==''thensection=nilend
 ifsectionthen
 excerpt=parser.getSectionTag(wikitext,section)
 ifnotexcerptthen
 ifparams.subsectionsthen
 excerpt=parser.getSection(wikitext,section)
 else
 localsections=parser.getSections(wikitext)
 excerpt=sections[section]
 end
 end
 ifnotexcerptthenreturnExcerpt.getError('section-not-found',section)end
 ifexcerpt==''thenreturnExcerpt.getError('section-empty',section)end
 else
 excerpt=parser.getLead(wikitext)
 ifexcerpt==''thenreturnExcerpt.getError('lead-empty')end
 end

 -- Remove noinclude bits
 excerpt=excerpt:gsub('<[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>.-</[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>','')

 -- Filter various elements from the excerpt
 excerpt=Excerpt.filterFiles(excerpt,params.files)
 excerpt=Excerpt.filterLists(excerpt,params.lists)
 excerpt=Excerpt.filterTables(excerpt,params.tables)
 excerpt=Excerpt.filterParagraphs(excerpt,params.paragraphs)

 -- If no file is found, try to get one from the infobox
 if(params.only=='file'orparams.only=='files'ornotparams.onlyand(notparams.filesorparams.files~='0'))-- caller asked for files
 andnotsection-- and we're in the lead section
 andconfig.captions-- and we have the config option required to try finding files in infoboxes
 and#parser.getFiles(excerpt)==0-- and there're no files in the excerpt
 then
 excerpt=Excerpt.addInfoboxFile(excerpt)
 end

 -- Filter the templates by appending the templates blacklist to the templates filter
 ifconfig.blacklistthen
 localblacklist=table.concat(config.blacklist,',')
 ifparams.templatesthen
 ifstring.sub(params.templates,1,1)=='-'then
 params.templates=params.templates..','..blacklist
 end
 else
 params.templates='-'..blacklist
 end
 end
 excerpt=Excerpt.filterTemplates(excerpt,params.templates)

 -- Leave only the requested elements
 ifparams.only=='file'orparams.only=='files'then
 localfiles=parser.getFiles(excerpt)
 excerpt=params.only=='file'andfiles[1]ortable.concat(files,'\n\n')
 end
 ifparams.only=='list'orparams.only=='lists'then
 locallists=parser.getLists(excerpt)
 excerpt=params.only=='list'andlists[1]ortable.concat(lists,'\n\n')
 end
 ifparams.only=='table'orparams.only=='tables'then
 localtables=parser.getTables(excerpt)
 excerpt=params.only=='table'andtables[1]ortable.concat(tables,'\n\n')
 end
 ifparams.only=='paragraph'orparams.only=='paragraphs'then
 localparagraphs=parser.getParagraphs(excerpt)
 excerpt=params.only=='paragraph'andparagraphs[1]ortable.concat(paragraphs,'\n\n')
 end
 ifparams.only=='template'orparams.only=='templates'then
 localtemplates=parser.getTemplates(excerpt)
 excerpt=params.only=='template'andtemplates[1]ortable.concat(templates,'\n\n')
 end

 -- @todo Make more robust and move downwards
 ifparams.briefDatesthen
 excerpt=Excerpt.fixDates(excerpt)
 end

 -- Remove unwanted elements
 excerpt=Excerpt.removeComments(excerpt)
 excerpt=Excerpt.removeSelfLinks(excerpt)
 excerpt=Excerpt.removeNonFreeFiles(excerpt)
 excerpt=Excerpt.removeBehaviorSwitches(excerpt)

 -- Fix or remove the references
 ifparams.referencesthen
 excerpt=Excerpt.fixReferences(excerpt,page,wikitext)
 else
 excerpt=Excerpt.removeReferences(excerpt)
 end

 -- Remove wikilinks
 ifnotparams.linksthen
 excerpt=Excerpt.removeLinks(excerpt)
 end

 -- Link the bold text near the start of most leads and then remove it
 ifnotsectionthen
 excerpt=Excerpt.linkBold(excerpt,page)
 end
 ifnotparams.boldthen
 excerpt=Excerpt.removeBold(excerpt)
 end

 -- Remove extra line breaks but leave one before and after so the parser interprets lists, tables, etc. correctly
 excerpt=excerpt:gsub('\n\n\n+','\n\n')
 excerpt=mw.text.trim(excerpt)
 excerpt='\n'..excerpt..'\n'

 -- Remove nested categories
 excerpt=frame:preprocess(excerpt)
 excerpt=Excerpt.removeCategories(excerpt)

 -- Add tracking categories
 ifparams.trackandconfig.categoriesthen
 excerpt=Excerpt.addTrackingCategories(excerpt)
 end

 -- Build the final output
 ifparams.inlinethen
 returnmw.text.trim(excerpt)
 end

 localtag=params.quoteand'blockquote'or'div'
 localblock=mw.html.create(tag):addClass('excerpt-block'):addClass(params.class)

 ifconfig.stylesthen
 localstyles=frame:extensionTag('templatestyles','',{src=config.styles})
 block:node(styles)
 end

 ifparams.hatthen
 localhat=Excerpt.getHat(page,section,params)
 block:node(hat)
 end

 excerpt=mw.html.create('div'):addClass('excerpt'):wikitext(excerpt)
 block:node(excerpt)

 ifparams.morethen
 localmore=Excerpt.getReadMore(page,section)
 block:node(more)
 end

 returnblock
 end

 -- Filter the files in the given wikitext against the given filter
 functionExcerpt.filterFiles(wikitext,filter)
 ifnotfilterthenreturnwikitextend
 localfilters,isBlacklist=Excerpt.parseFilter(filter)
 localfiles=parser.getFiles(wikitext)
 forindex,fileinpairs(files)do
 localname=parser.getFileName(file)
 ifisBlacklistand(Excerpt.matchFilter(index,filters)orExcerpt.matchFilter(name,filters))
 ornotisBlacklistand(notExcerpt.matchFilter(index,filters)andnotExcerpt.matchFilter(name,filters))then
 wikitext=Excerpt.removeString(wikitext,file)
 end
 end
 returnwikitext
 end

 -- Filter the lists in the given wikitext against the given filter
 functionExcerpt.filterLists(wikitext,filter)
 ifnotfilterthenreturnwikitextend
 localfilters,isBlacklist=Excerpt.parseFilter(filter)
 locallists=parser.getLists(wikitext)
 forindex,listinpairs(lists)do
 ifisBlacklistandExcerpt.matchFilter(index,filters)
 ornotisBlacklistandnotExcerpt.matchFilter(index,filters)then
 wikitext=Excerpt.removeString(wikitext,list)
 end
 end
 returnwikitext
 end

 -- Filter the tables in the given wikitext against the given filter
 functionExcerpt.filterTables(wikitext,filter)
 ifnotfilterthenreturnwikitextend
 localfilters,isBlacklist=Excerpt.parseFilter(filter)
 localtables=parser.getTables(wikitext)
 forindex,tableWikitextinpairs(tables)do
 localid=parser.getTableAttribute(tableWikitext,'id')
 ifisBlacklistand(Excerpt.matchFilter(index,filters)orExcerpt.matchFilter(id,filters))
 ornotisBlacklistand(notExcerpt.matchFilter(index,filters)andnotExcerpt.matchFilter(id,filters))then
 wikitext=Excerpt.removeString(wikitext,tableWikitext)
 end
 end
 returnwikitext
 end

 -- Filter the paragraphs in the given wikitext against the given filter
 functionExcerpt.filterParagraphs(wikitext,filter)
 ifnotfilterthenreturnwikitextend
 localfilters,isBlacklist=Excerpt.parseFilter(filter)
 localparagraphs=parser.getParagraphs(wikitext)
 forindex,paragraphinpairs(paragraphs)do
 ifisBlacklistandExcerpt.matchFilter(index,filters)
 ornotisBlacklistandnotExcerpt.matchFilter(index,filters)then
 wikitext=Excerpt.removeString(wikitext,paragraph)
 end
 end
 returnwikitext
 end

 -- Filter the templates in the given wikitext against the given filter
 functionExcerpt.filterTemplates(wikitext,filter)
 ifnotfilterthenreturnwikitextend
 localfilters,isBlacklist=Excerpt.parseFilter(filter)
 localtemplates=parser.getTemplates(wikitext)
 forindex,templateinpairs(templates)do
 localname=parser.getTemplateName(template)
 ifisBlacklistand(Excerpt.matchFilter(index,filters)orExcerpt.matchFilter(name,filters))
 ornotisBlacklistand(notExcerpt.matchFilter(index,filters)andnotExcerpt.matchFilter(name,filters))then
 wikitext=Excerpt.removeString(wikitext,template)
 end
 end
 returnwikitext
 end

 functionExcerpt.addInfoboxFile(excerpt)
 -- We cannot distinguish the infobox from the other templates, so we search them all
 localtemplates=parser.getTemplates(excerpt)
 for_,templateinpairs(templates)do
 localparameters=parser.getTemplateParameters(template)
 localfile,captions,caption,cssClasses,cssClass
 for_,pairinpairs(config.captions)do
 file=pair[1]
 file=parameters[file]
 iffileandExcerpt.matchAny(file,'^.*%.',{'[Jj][Pp][Ee]?[Gg]','[Pp][Nn][Gg]','[Gg][Ii][Ff]','[Ss][Vv][Gg]'},'.*')then
 file=string.match(file,'%[?%[?.-:([^{|]+)%]?%]?')orfile-- [[File:Example.jpg{{!}}upright=1.5]] to Example.jpg
 captions=pair[2]
 for_,pinpairs(captions)do
 ifparameters[p]thencaption=parameters[p]breakend
 end
 -- Check for CSS classes
 -- We opt to use skin-invert-image instead of skin-invert
 -- in all other cases, the CSS provided in the infobox is used
 ifpair[3]then
 cssClasses=pair[3]
 for_,pinpairs(cssClasses)do
 ifparameters[p]then
 cssClass=(parameters[p]=='skin-invert')and'skin-invert-image'orparameters[p]
 break
 end
 end
 end
 localclass=cssClassand('|class='..cssClass)or''
 return'[[File:'..file..class..'|thumb|'..(captionor'')..']]'..excerpt
 end
 end
 end
 returnexcerpt
 end

 functionExcerpt.removeNonFreeFiles(wikitext)
 localfiles=parser.getFiles(wikitext)
 for_,fileinpairs(files)do
 localfileName='File:'..parser.getFileName(file)
 localfileTitle=mw.title.new(fileName)
 iffileTitlethen
 localfileDescription=fileTitle:getContent()
 ifnotfileDescriptionorfileDescription==''then
 localframe=mw.getCurrentFrame()
 fileDescription=frame:preprocess('{{'..fileName..'}}')-- try Commons
 end
 iffileDescriptionandstring.match(fileDescription,'[Nn]on%-free')then
 wikitext=Excerpt.removeString(wikitext,file)
 end
 end
 end
 returnwikitext
 end

 functionExcerpt.getHat(page,section,params)
 localhat

 -- Build the text
 ifparams.thisthen
 hat=params.this
 elseifparams.quotethen
 hat=Excerpt.getMessage('this')
 elseifparams.onlythen
 hat=Excerpt.getMessage(params.only)
 else
 hat=Excerpt.getMessage('section')
 end
 hat=hat..' '..Excerpt.getMessage('excerpt')

 -- Build the link
 ifsectionthen
 hat=hat..' [[:'..page..'#'..mw.uri.anchorEncode(section)..'|'..params.displayTitle
 ..' § '..section:gsub('%[%[([^]|]+)|?[^]]*%]%]','%1')..']].'-- remove nested links
 else
 hat=hat..' [[:'..page..'|'..params.displayTitle..']].'
 end

 -- Build the edit link
 localtitle=mw.title.new(page)
 localeditUrl=title:fullUrl('action=edit')
 hat=hat..'<span class="mw-editsection-like plainlinks"><span class="mw-editsection-bracket">[</span>['
 hat=hat..editUrl..' '..mw.message.new('editsection'):plain()
 hat=hat..']<span class="mw-editsection-bracket">]</span></span>'

 ifconfig.hatthen
 localframe=mw.getCurrentFrame()
 hat=config.hat..hat..'}}'
 hat=frame:preprocess(hat)
 else
 hat=mw.html.create('div'):addClass('dablink excerpt-hat'):wikitext(hat)
 end

 returnhat
 end

 functionExcerpt.getReadMore(page,section)
 locallink="'''[["..page
 ifsectionthen
 link=link..'#'..section
 end
 localtext=Excerpt.getMessage('more')
 link=link..'|'..text.."]]'''"
 link=mw.html.create('div'):addClass('noprint excerpt-more'):wikitext(link)
 returnlink
 end

 -- Fix birth and death dates, but only in the first paragraph
 -- @todo Use parser.getParagraphs() to get the first paragraph
 functionExcerpt.fixDates(excerpt)
 localstart=1-- skip initial templates
 locals
 locale=0
 repeat
 start=e+1
 s,e=mw.ustring.find(excerpt,'%s*%b{}%s*',start)
 untilnotsors>start
 s,e=mw.ustring.find(excerpt,'%b()',start)-- get (...), which may be (year–year)
 ifsands<start+100then-- look only near the start
 localexcerptStart=mw.ustring.sub(excerpt,s,e)
 localyear1,conjunction,year2=string.match(excerptStart,'(%d%d%d+)(.-)(%d%d%d+)')
 ifyear1andyear2and(string.match(conjunction,'[%-–—]')orstring.match(conjunction,'{{%s*[sS]nd%s*}}'))then
 localy1=tonumber(year1)
 localy2=tonumber(year2)
 ify2>y1andy2<y1+125andy1<=tonumber(os.date('%Y'))then
 excerpt=mw.ustring.sub(excerpt,1,s)..year1..'–'..year2..mw.ustring.sub(excerpt,e)
 end
 end
 end
 returnexcerpt
 end

 -- Replace the first call to each reference defined outside of the excerpt for the full reference, to prevent undefined references
 -- Then prefix the page title to the reference names to prevent conflicts
 -- that is, replace <ref name="Foo"> for <ref name="Title of the article Foo">
 -- and also <ref name="Foo" /> for <ref name="Title of the article Foo" />
 -- also remove reference groups: <ref name="Foo" group="Bar"> for <ref name="Title of the article Foo">
 -- and <ref group="Bar"> for <ref>
 -- @todo The current regex may fail in cases with both kinds of quotes, like <ref name="Darwin's book">
 functionExcerpt.fixReferences(excerpt,page,wikitext)
 localreferences=parser.getReferences(excerpt)
 localfixed={}
 for_,referenceinpairs(references)do
 localname=parser.getTagAttribute(reference,'name')
 ifnotfixed[name]then-- fix each reference only once
 localcontent=parser.getTagContent(reference)
 ifnotcontentthen-- reference is self-closing
 localfull=parser.getReference(excerpt,name)
 ifnotfullthen-- the reference is not defined in the excerpt
 full=parser.getReference(wikitext,name)
 iffullthen
 excerpt=excerpt:gsub(Excerpt.escapeString(reference),Excerpt.escapeString(full),1)
 end
 table.insert(fixed,name)
 end
 end
 end
 end
 -- Prepend the page title to the reference names to prevent conflicts with other references in the transcluding page
 excerpt=excerpt:gsub('< *[Rr][Ee][Ff][^>]*name *= *["\']?([^"\'>/]+)["\']?[^>/]*(/?) *>','<ref name="'..page:gsub('"','')..' %1"%2>')
 -- Remove reference groups because they don't apply to the transcluding page
 excerpt=excerpt:gsub('< *[Rr][Ee][Ff] *group *= *["\']?[^"\'>/]+["\'] *>','<ref>')
 returnexcerpt
 end

 functionExcerpt.removeReferences(excerpt)
 localreferences=parser.getReferences(excerpt)
 for_,referenceinpairs(references)do
 excerpt=Excerpt.removeString(excerpt,reference)
 end
 returnexcerpt
 end

 functionExcerpt.removeCategories(excerpt)
 localcategories=parser.getCategories(excerpt)
 for_,categoryinpairs(categories)do
 excerpt=Excerpt.removeString(excerpt,category)
 end
 returnexcerpt
 end

 functionExcerpt.removeBehaviorSwitches(excerpt)
 returnexcerpt:gsub('__[A-Z]+__','')
 end

 functionExcerpt.removeComments(excerpt)
 returnexcerpt:gsub('<!%-%-.-%-%->','')
 end

 functionExcerpt.removeBold(excerpt)
 returnexcerpt:gsub("'''",'')
 end

 functionExcerpt.removeLinks(excerpt)
 locallinks=parser.getLinks(excerpt)
 for_,linkinpairs(links)do
 excerpt=Excerpt.removeString(excerpt,link)
 end
 returnexcerpt
 end

 -- @todo Use parser.getLinks
 functionExcerpt.removeSelfLinks(excerpt)
 locallang=mw.language.getContentLanguage()
 localpage=Excerpt.escapeString(mw.title.getCurrentTitle().prefixedText)
 localucpage=lang:ucfirst(page)
 locallcpage=lang:lcfirst(page)
 excerpt=excerpt
 :gsub('%[%[('..ucpage..')%]%]','%1')
 :gsub('%[%[('..lcpage..')%]%]','%1')
 :gsub('%[%['..ucpage..'|([^]]+)%]%]','%1')
 :gsub('%[%['..lcpage..'|([^]]+)%]%]','%1')
 returnexcerpt
 end

 -- Replace the bold title or synonym near the start of the page by a link to the page
 functionExcerpt.linkBold(excerpt,page)
 locallang=mw.language.getContentLanguage()
 localposition=mw.ustring.find(excerpt,"'''"..lang:ucfirst(page).."'''",1,true)-- look for "'''Foo''' is..." (uc) or "A '''foo''' is..." (lc)
 ormw.ustring.find(excerpt,"'''"..lang:lcfirst(page).."'''",1,true)-- plain search: special characters in page represent themselves
 ifpositionthen
 locallength=mw.ustring.len(page)
 excerpt=mw.ustring.sub(excerpt,1,position+2)..'[['..mw.ustring.sub(excerpt,position+3,position+length+2)..']]'..mw.ustring.sub(excerpt,position+length+3,-1)-- link it
 else-- look for anything unlinked in bold, assumed to be a synonym of the title (e.g. a person's birth name)
 excerpt=mw.ustring.gsub(excerpt,"'''(.-'*)'''",function(text)
 ifnotstring.find(text,'%[')andnotstring.find(text,'%{')then-- if not wikilinked or some weird template
 return"'''[["..page..'|'..text.."]]'''"-- replace '''Foo''' by '''[[page|Foo]]'''
 else
 returnnil-- instruct gsub to make no change
 end
 end,1)-- terminates the anonymous replacement function passed to gsub
 end
 returnexcerpt
 end

 functionExcerpt.addTrackingCategories(excerpt)
 localcurrentTitle=mw.title.getCurrentTitle()
 localcontentCategory=config.categories.content
 ifcontentCategoryandcurrentTitle.isContentPagethen
 excerpt=excerpt..'[[Category:'..contentCategory..']]'
 end
 localnamespaceCategory=config.categories[currentTitle.namespace]
 ifnamespaceCategorythen
 excerpt=excerpt..'[[Category:'..namespaceCategory..']]'
 end
 returnexcerpt
 end

 -- Helper method to match from a list of regular expressions
 -- Like so: match pre..list[1]..post or pre..list[2]..post or ...
 functionExcerpt.matchAny(text,pre,list,post,init)
 localmatch={}
 fori=1,#listdo
 match={mw.ustring.match(text,pre..list[i]..post,init)}
 ifmatch[1]thenreturnunpack(match)end
 end
 returnnil
 end

 -- Helper function to get arguments
 -- args from Lua calls have priority over parent args from template
 functionExcerpt.getArg(key,default)
 localframe=mw.getCurrentFrame()
 fork,valueinpairs(frame:getParent().args)do
 ifk==keyandmw.text.trim(value)~=''then
 returnvalue
 end
 end
 fork,valueinpairs(frame.args)do
 ifk==keyandmw.text.trim(value)~=''then
 returnvalue
 end
 end
 returndefault
 end

 -- Helper method to get an error message
 -- This method also categorizes the current page in one of the configured error categories
 functionExcerpt.getError(key,value)
 localmessage=Excerpt.getMessage('error-'..key,value)
 localmarkup=mw.html.create('div'):addClass('error'):wikitext(message)
 ifconfig.categoriesandconfig.categories.errorsandmw.title.getCurrentTitle().isContentPagethen
 markup:node('[[Category:'..config.categories.errors..']]')
 end
 returnmarkup
 end

 -- Helper method to get a localized message
 -- This method uses Module:TNT to get localized messages from https://commons.wikimedia.org/wiki/Data:I18n/Module:Excerpt.tab
 -- If Module:TNT is not available or the localized message does not exist, the key is returned instead
 functionExcerpt.getMessage(key,value)
 localok,TNT=pcall(require,'Module:TNT')
 ifnotokthenreturnkeyend
 localok2,message=pcall(TNT.format,'I18n/Module:Excerpt.tab',key,value)
 ifnotok2thenreturnkeyend
 returnmessage
 end

 -- Helper method to escape a string for use in regexes
 functionExcerpt.escapeString(str)
 returnstr:gsub('[%^%$%(%)%.%[%]%*%+%-%?%%]','%%%0')
 end

 -- Helper method to remove a string from a text
 -- @param text Text from where to remove the string
 -- @param str String to remove
 -- @return The given text with the string removed
 functionExcerpt.removeString(text,str)
 localpattern=Excerpt.escapeString(str)
 if#pattern>9999then-- strings longer than 10000 bytes can't be put into regexes
 pattern=Excerpt.escapeString(mw.ustring.sub(str,1,999))..'.-'..Excerpt.escapeString(mw.ustring.sub(str,-999))
 end
 returntext:gsub(pattern,'')
 end

 -- Helper method to convert a comma-separated list of numbers or min-max ranges into a list of booleans
 -- @param filter Required. Comma-separated list of numbers or min-max ranges, for example '1,3-5'
 -- @return Map from integers to booleans, for example {1=true,2=false,3=true,4=true,5=true}
 -- @return Boolean indicating whether the filters should be treated as a blacklist or not
 -- @note Merging this into matchFilter is possible, but way too inefficient
 functionExcerpt.parseFilter(filter)
 localfilters={}
 localisBlacklist=false
 ifstring.sub(filter,1,1)=='-'then
 isBlacklist=true
 filter=string.sub(filter,2)
 end
 localvalues=mw.text.split(filter,',')-- split values: '1,3-5' to {'1','3-5'}
 for_,valueinpairs(values)do
 value=mw.text.trim(value)
 localmin,max=mw.ustring.match(value,'^(%d+)%s*[-–—]%s*(%d+)$')-- '3-5' to min=3 max=5
 ifnotmaxthenmin,max=string.match(value,'^((%d+))$')end-- '1' to min=1 max=1
 ifmaxthen
 fori=min,maxdofilters[i]=trueend
 else
 filters[value]=true-- if we reach this point, the string had the form 'a,b,c' rather than '1,2,3'
 end
 end
 localfilter={cache={},terms=filters}
 returnfilter,isBlacklist
 end

 -- Helper function to see if a value matches any of the given filters
 functionExcerpt.matchFilter(value,filter)
 ifvalue==nilthen
 returnfalse
 elseiftype(value)=="number"then
 returnfilter.terms[value]
 else
 localcached=filter.cache[value]
 ifcached~=nilthen
 returncached
 end
 locallang=mw.language.getContentLanguage()
 locallcvalue=lang:lcfirst(value)
 localucvalue=lang:ucfirst(value)
 forterminpairs(filter.terms)do
 ifvalue==tostring(term)
 ortype(term)=="string"and(
 lcvalue==term
 orucvalue==term
 ormw.ustring.match(value,term)
 )then
 filter.cache[value]=true
 returntrue
 end
 end
 filter.cache[value]=false
 end
 end

 returnExcerpt

AltStyle によって変換されたページ (->オリジナル) /