<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://zhdeletionpedia.toolforge.org/w/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FUtilities</id>
	<title>Module:Citation/CS1/Utilities - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://zhdeletionpedia.toolforge.org/w/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FUtilities"/>
	<link rel="alternate" type="text/html" href="https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Utilities&amp;action=history"/>
	<updated>2026-09-22T01:18:06Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Utilities&amp;diff=7182&amp;oldid=prev</id>
		<title>Shizhao：​已从:w:Module:Citation/CS1/Utilities导入1个版本</title>
		<link rel="alternate" type="text/html" href="https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Utilities&amp;diff=7182&amp;oldid=prev"/>
		<updated>2023-04-06T14:40:38Z</updated>

		<summary type="html">&lt;p&gt;已从&lt;a href=&quot;https://zh.wikipedia.org/wiki/Module:Citation/CS1/Utilities&quot; class=&quot;extiw&quot; title=&quot;w:Module:Citation/CS1/Utilities&quot;&gt;w:Module:Citation/CS1/Utilities&lt;/a&gt;导入1个版本&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年4月6日 (四) 14:40的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;zh&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;（没有差异）&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Shizhao</name></author>
	</entry>
	<entry>
		<id>https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Utilities&amp;diff=7181&amp;oldid=prev</id>
		<title>w&gt;Antigng：​ep: 71332844</title>
		<link rel="alternate" type="text/html" href="https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Utilities&amp;diff=7181&amp;oldid=prev"/>
		<updated>2022-04-26T16:29:49Z</updated>

		<summary type="html">&lt;p&gt;&lt;a href=&quot;/w/index.php?title=WP:PP&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;WP:PP（页面不存在）&quot;&gt;ep&lt;/a&gt;: &lt;a href=&quot;/Special:%E5%B7%AE%E5%BC%82/71332844&quot; title=&quot;Special:差异/71332844&quot;&gt;71332844&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[--------------------------&amp;lt; F O R W A R D   D E C L A R A T I O N S &amp;gt;--------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local cfg;																		-- table of tables imported from selected Module:Citation/CS1/Configuration&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H Y P H E N _ T O _ D A S H &amp;gt;-------------------------------------------------&lt;br /&gt;
Converts a hyphen to a dash&lt;br /&gt;
]]&lt;br /&gt;
-- &lt;br /&gt;
local function hyphen_to_dash( str )&lt;br /&gt;
	if not is_set(str) or str:match( &amp;quot;[%[%]{}&amp;lt;&amp;gt;]&amp;quot; ) ~= nil then&lt;br /&gt;
		return str;&lt;br /&gt;
	end	&lt;br /&gt;
	return str:gsub( '-', '–' );&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S _ S E T &amp;gt;------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string.&lt;br /&gt;
This function is global because it is called from both this module and from Date validation&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
function is_set( var )&lt;br /&gt;
	return not (var == nil or var == '');&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; F I R S T _ S E T &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Locates and returns the first set value in a table of values where the order established in the table,&lt;br /&gt;
left-to-right (or top-to-bottom), is the order in which the values are evaluated.  Returns nil if none are set.&lt;br /&gt;
&lt;br /&gt;
This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs.  With the pairs&lt;br /&gt;
version the order of evaluation could not be guaranteed.  With the ipairs version, a nil value would terminate&lt;br /&gt;
the for-loop before it reached the actual end of the list.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function first_set (list, count)&lt;br /&gt;
	local i = 1;&lt;br /&gt;
	while i &amp;lt;= count do															-- loop through all items in list&lt;br /&gt;
		if is_set( list[i] ) then&lt;br /&gt;
			return list[i];														-- return the first set list member&lt;br /&gt;
		end&lt;br /&gt;
		i = i + 1;																-- point to next&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I N _ A R R A Y &amp;gt;--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Whether needle is in haystack&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function in_array( needle, haystack )&lt;br /&gt;
	if needle == nil then&lt;br /&gt;
		return false;&lt;br /&gt;
	end&lt;br /&gt;
	for n,v in ipairs( haystack ) do&lt;br /&gt;
		if v == needle then&lt;br /&gt;
			return n;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S U B S T I T U T E &amp;gt;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Populates numbered arguments in a message string using an argument table.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function substitute( msg, args )&lt;br /&gt;
	return args and mw.message.newRawMessage( msg, args ):plain() or msg;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H A S _ A C C E P T _ A S _ W R I T T E N &amp;gt;------------------------------------&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;str&amp;gt; is wholly wrapped in accept-as-written markup, return &amp;lt;str&amp;gt; without markup and true; return &amp;lt;str&amp;gt; and false else&lt;br /&gt;
&lt;br /&gt;
with allow_empty = false, &amp;lt;str&amp;gt; must have at least one character inside the markup&lt;br /&gt;
with allow_empty = true, &amp;lt;str&amp;gt; the markup frame can be empty like (()) to distinguish an empty template parameter from the specific condition &amp;quot;has no applicable value&amp;quot; in citation-context.&lt;br /&gt;
&lt;br /&gt;
After further evaluation the two cases might be merged at a later stage, but should be kept separated for now.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function has_accept_as_written (str, allow_empty)&lt;br /&gt;
	local count;&lt;br /&gt;
	if true == allow_empty then&lt;br /&gt;
		str, count = str:gsub ('^%(%((.*)%)%)$', '%1'); 						-- allows (()) to be an empty set&lt;br /&gt;
	else&lt;br /&gt;
		str, count = str:gsub ('^%(%((.+)%)%)$', '%1');&lt;br /&gt;
	end&lt;br /&gt;
	return str, 0 ~= count;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S A F E _ F O R _ I T A L I C S &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Protects a string that will be wrapped in wiki italic markup '' ... ''&lt;br /&gt;
&lt;br /&gt;
Note: We cannot use &amp;lt;i&amp;gt; for italics, as the expected behavior for italics specified by ''...'' in the title is that&lt;br /&gt;
they will be inverted (i.e. unitalicized) in the resulting references.  In addition, &amp;lt;i&amp;gt; and '' tend to interact&lt;br /&gt;
poorly under Mediawiki's HTML tidy.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function safe_for_italics (str)&lt;br /&gt;
	if not is_set (str) then return str end&lt;br /&gt;
&lt;br /&gt;
	if str:sub (1, 1) == &amp;quot;'&amp;quot; then str = &amp;quot;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;quot; .. str; end&lt;br /&gt;
	if str:sub (-1, -1) == &amp;quot;'&amp;quot; then str = str .. &amp;quot;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;quot;; end&lt;br /&gt;
	&lt;br /&gt;
	-- Remove newlines as they break italics.&lt;br /&gt;
	return str:gsub ('\n', ' ');&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; W R A P _ S T Y L E &amp;gt;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Applies styling to various parameters.  Supplied string is wrapped using a message_list configuration taking one&lt;br /&gt;
argument; protects italic styled parameters.  Additional text taken from citation_config.presentation - the reason&lt;br /&gt;
this function is similar to but separate from wrap_msg().&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function wrap_style (key, str)&lt;br /&gt;
	if not is_set (str) then&lt;br /&gt;
		return '';&lt;br /&gt;
	elseif in_array (key, cfg.presentation['_safe_for_italics']) then&lt;br /&gt;
		str = safe_for_italics (str);&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return substitute (cfg.presentation[key], str);&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; M A K E _ S E P _ L I S T &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
make a separated list of items using provided separators.&lt;br /&gt;
	&amp;lt;sep_list&amp;gt; - typically '&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;'&lt;br /&gt;
	&amp;lt;sep_list_pair&amp;gt; - typically '&amp;lt;space&amp;gt;and&amp;lt;space&amp;gt;'&lt;br /&gt;
	&amp;lt;sep_list_end&amp;gt; - typically '&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;and&amp;lt;space&amp;gt;' or '&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;&amp;amp;&amp;lt;space&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
defaults to cfg.presentation['sep_list'], cfg.presentation['sep_list_pair'], and cfg.presentation['sep_list_end']&lt;br /&gt;
if &amp;lt;sep_list_end&amp;gt; is specified, &amp;lt;sep_list&amp;gt; and &amp;lt;sep_list_pair&amp;gt; must also be supplied&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function make_sep_list (count, list_seq, sep_list, sep_list_pair, sep_list_end)&lt;br /&gt;
	local list = '';&lt;br /&gt;
&lt;br /&gt;
	if not sep_list then														-- set the defaults&lt;br /&gt;
		sep_list = cfg.presentation['sep_list'];&lt;br /&gt;
		sep_list_pair = cfg.presentation['sep_list_pair'];&lt;br /&gt;
		sep_list_end = cfg.presentation['sep_list_end'];&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if 2 &amp;gt;= count then&lt;br /&gt;
		list = table.concat (list_seq, sep_list_pair);							-- insert separator between two items; returns list_seq[1] then only one item&lt;br /&gt;
	elseif 2 &amp;lt; count then&lt;br /&gt;
		list = table.concat (list_seq, sep_list, 1, count - 1);					-- concatenate all but last item with plain list separator&lt;br /&gt;
		list = table.concat ({list, list_seq[count]}, sep_list_end);			-- concatenate last item onto end of &amp;lt;list&amp;gt; with final separator&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return list;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S A F E _ J O I N &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Joins a sequence of strings together while checking for duplicate separation characters.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function safe_join( tbl, duplicate_char )&lt;br /&gt;
	--[[&lt;br /&gt;
	Note: we use string functions here, rather than ustring functions.&lt;br /&gt;
	&lt;br /&gt;
	This has considerably faster performance and should work correctly as &lt;br /&gt;
	long as the duplicate_char is strict ASCII.  The strings&lt;br /&gt;
	in tbl may be ASCII or UTF8.&lt;br /&gt;
	]]&lt;br /&gt;
	&lt;br /&gt;
	local str = '';																-- the output string&lt;br /&gt;
	local comp = '';															-- what does 'comp' mean?&lt;br /&gt;
	local end_chr = '';&lt;br /&gt;
	local trim;&lt;br /&gt;
	for _, value in ipairs( tbl ) do&lt;br /&gt;
		if value == nil then value = ''; end&lt;br /&gt;
		&lt;br /&gt;
		if str == '' then														-- if output string is empty&lt;br /&gt;
			str = value;														-- assign value to it (first time through the loop)&lt;br /&gt;
		elseif value ~= '' then&lt;br /&gt;
			if value:sub(1,1) == '&amp;lt;' then										-- Special case of values enclosed in spans and other markup.&lt;br /&gt;
				comp = value:gsub( &amp;quot;%b&amp;lt;&amp;gt;&amp;quot;, &amp;quot;&amp;quot; );								-- remove html markup (&amp;lt;span&amp;gt;string&amp;lt;/span&amp;gt; -&amp;gt; string)&lt;br /&gt;
			else&lt;br /&gt;
				comp = value;&lt;br /&gt;
			end&lt;br /&gt;
																				-- typically duplicate_char is sepc&lt;br /&gt;
			if comp:sub(1,1) == duplicate_char then								-- is first charactier same as duplicate_char? why test first character?&lt;br /&gt;
																				--   Because individual string segments often (always?) begin with terminal punct for th&lt;br /&gt;
																				--   preceding segment: 'First element' .. 'sepc next element' .. etc?&lt;br /&gt;
				trim = false;&lt;br /&gt;
				end_chr = str:sub(-1,-1);										-- get the last character of the output string&lt;br /&gt;
				-- str = str .. &amp;quot;&amp;lt;HERE(enchr=&amp;quot; .. end_chr.. &amp;quot;)&amp;quot;					-- debug stuff?&lt;br /&gt;
				if end_chr == duplicate_char then								-- if same as separator&lt;br /&gt;
					str = str:sub(1,-2);										-- remove it&lt;br /&gt;
				elseif end_chr == &amp;quot;'&amp;quot; then										-- if it might be wikimarkup&lt;br /&gt;
					if str:sub(-3,-1) == duplicate_char .. &amp;quot;''&amp;quot; then			-- if last three chars of str are sepc'' &lt;br /&gt;
						str = str:sub(1, -4) .. &amp;quot;''&amp;quot;;							-- remove them and add back ''&lt;br /&gt;
					elseif str:sub(-5,-1) == duplicate_char .. &amp;quot;]]''&amp;quot; then		-- if last five chars of str are sepc]]'' &lt;br /&gt;
						trim = true;											-- why? why do this and next differently from previous?&lt;br /&gt;
					elseif str:sub(-4,-1) == duplicate_char .. &amp;quot;]''&amp;quot; then		-- if last four chars of str are sepc]'' &lt;br /&gt;
						trim = true;											-- same question&lt;br /&gt;
					end&lt;br /&gt;
				elseif end_chr == &amp;quot;]&amp;quot; then										-- if it might be wikimarkup&lt;br /&gt;
					if str:sub(-3,-1) == duplicate_char .. &amp;quot;]]&amp;quot; then			-- if last three chars of str are sepc]] wikilink &lt;br /&gt;
						trim = true;&lt;br /&gt;
					elseif str:sub(-2,-1) == duplicate_char .. &amp;quot;]&amp;quot; then			-- if last two chars of str are sepc] external link&lt;br /&gt;
						trim = true;&lt;br /&gt;
					elseif str:sub(-4,-1) == duplicate_char .. &amp;quot;'']&amp;quot; then		-- normal case when |url=something &amp;amp; |title=Title.&lt;br /&gt;
						trim = true;&lt;br /&gt;
					end&lt;br /&gt;
				elseif end_chr == &amp;quot; &amp;quot; then										-- if last char of output string is a space&lt;br /&gt;
					if str:sub(-2,-1) == duplicate_char .. &amp;quot; &amp;quot; then				-- if last two chars of str are &amp;lt;sepc&amp;gt;&amp;lt;space&amp;gt;&lt;br /&gt;
						str = str:sub(1,-3);									-- remove them both&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if trim then&lt;br /&gt;
					if value ~= comp then 										-- value does not equal comp when value contains html markup&lt;br /&gt;
						local dup2 = duplicate_char;&lt;br /&gt;
						if dup2:match( &amp;quot;%A&amp;quot; ) then dup2 = &amp;quot;%&amp;quot; .. dup2; end		-- if duplicate_char not a letter then escape it&lt;br /&gt;
						&lt;br /&gt;
						value = value:gsub( &amp;quot;(%b&amp;lt;&amp;gt;)&amp;quot; .. dup2, &amp;quot;%1&amp;quot;, 1 )			-- remove duplicate_char if it follows html markup&lt;br /&gt;
					else&lt;br /&gt;
						value = value:sub( 2, -1 );								-- remove duplicate_char when it is first character&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			str = str .. value;													--add it to the output string&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return str;&lt;br /&gt;
end  &lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S T R I P _ A P O S T R O P H E _ M A R K U P &amp;gt;--------------------------------&lt;br /&gt;
&lt;br /&gt;
Strip wiki italic and bold markup from argument so that it doesn't contaminate COinS metadata.&lt;br /&gt;
This function strips common patterns of apostrophe markup.  We presume that editors who have taken the time to&lt;br /&gt;
markup a title have, as a result, provided valid markup. When they don't, some single apostrophes are left behind.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function strip_apostrophe_markup (argument)&lt;br /&gt;
	if not is_set (argument) then return argument; end&lt;br /&gt;
&lt;br /&gt;
	while true do&lt;br /&gt;
		if argument:match (&amp;quot;%'%'%'%'%'&amp;quot;) then									-- bold italic (5)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%'%'%'%'%'&amp;quot;, &amp;quot;&amp;quot;);							-- remove all instances of it&lt;br /&gt;
		elseif argument:match (&amp;quot;%'%'%'%'&amp;quot;) then									-- italic start and end without content (4)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%'%'%'%'&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
		elseif argument:match (&amp;quot;%'%'%'&amp;quot;) then									-- bold (3)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%'%'%'&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
		elseif argument:match (&amp;quot;%'%'&amp;quot;) then										-- italic (2)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%'%'&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
		else&lt;br /&gt;
			break;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return argument;															-- done&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H A S _ I N V I S I B L E _ C H A R S &amp;gt;----------------------------------------&lt;br /&gt;
&lt;br /&gt;
This function searches a parameter's value for nonprintable or invisible characters.  The search stops at the&lt;br /&gt;
first match.&lt;br /&gt;
&lt;br /&gt;
This function will detect the visible replacement character when it is part of the wikisource.&lt;br /&gt;
&lt;br /&gt;
Detects but ignores nowiki and math stripmarkers.  Also detects other named stripmarkers (gallery, math, pre, ref)&lt;br /&gt;
and identifies them with a slightly different error message.  See also coins_cleanup().&lt;br /&gt;
&lt;br /&gt;
Detects but ignores the character pattern that results from the transclusion of {{'}} templates.&lt;br /&gt;
&lt;br /&gt;
Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker&lt;br /&gt;
that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the&lt;br /&gt;
parameter value.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function has_invisible_chars (param, v)&lt;br /&gt;
	local position = '';														-- position of invisible char or starting position of stripmarker&lt;br /&gt;
	local dummy;																-- end of matching string; not used but required to hold end position when a capture is returned&lt;br /&gt;
	local capture;																-- used by stripmarker detection to hold name of the stripmarker&lt;br /&gt;
	local i=1;&lt;br /&gt;
	local stripmarker, apostrophe;&lt;br /&gt;
&lt;br /&gt;
	while cfg.invisible_chars[i] do&lt;br /&gt;
		local char=cfg.invisible_chars[i][1]									-- the character or group name&lt;br /&gt;
		local pattern=cfg.invisible_chars[i][2]									-- the pattern used to find it&lt;br /&gt;
		position, dummy, capture = mw.ustring.find (v, pattern)					-- see if the parameter value contains characters that match the pattern&lt;br /&gt;
		&lt;br /&gt;
		if position then&lt;br /&gt;
			if 'nowiki' == capture or 'math' == capture or						-- nowiki and math stripmarkers (not an error condition)&lt;br /&gt;
				('templatestyles' == capture) then	-- templatestyles stripmarker allowed&lt;br /&gt;
					stripmarker = true;											-- set a flag&lt;br /&gt;
			elseif true == stripmarker and 'delete' == char then				-- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker&lt;br /&gt;
				position = nil;													-- unset&lt;br /&gt;
			elseif 'apostrophe' == char then									-- apostrophe template uses &amp;amp;zwj;, hair space and zero-width space&lt;br /&gt;
				apostrophe = true;&lt;br /&gt;
			elseif true == apostrophe and in_array (char, {'zero width joiner', 'zero width space', 'hair space'}) then&lt;br /&gt;
				position = nil;													-- unset&lt;br /&gt;
			else&lt;br /&gt;
				local err_msg;&lt;br /&gt;
				if capture then&lt;br /&gt;
					err_msg = capture .. ' ' .. cfg.invisible_chars[i][3] or char;&lt;br /&gt;
				else&lt;br /&gt;
					err_msg = cfg.invisible_chars[i][3] or (char .. ' character');&lt;br /&gt;
				end&lt;br /&gt;
				return {err_msg, wrap_style ('parameter', param), position};	-- and done with this parameter&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		i=i+1;																	-- bump our index&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; W R A P _ M S G &amp;gt;--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Applies additional message text to various parameter values. Supplied string is wrapped using a message_list&lt;br /&gt;
configuration taking one argument.  Supports lower case text for {{citation}} templates.  Additional text taken&lt;br /&gt;
from citation_config.messages - the reason this function is similar to but separate from wrap_style().&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function wrap_msg (key, str, lower)&lt;br /&gt;
	if not is_set (str) then&lt;br /&gt;
		return '';&lt;br /&gt;
	elseif in_array (key, cfg.messages['_safe_for_italics']) then&lt;br /&gt;
		str = safe_for_italics (str);&lt;br /&gt;
	end&lt;br /&gt;
	if true == lower then&lt;br /&gt;
		local msg;&lt;br /&gt;
		msg = cfg.messages[key]:lower();										-- set the message to lower case before &lt;br /&gt;
		return substitute (msg, str);											-- including template text&lt;br /&gt;
	else&lt;br /&gt;
		return substitute (cfg.messages[key], str);&lt;br /&gt;
	end		&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; K E R N _ Q U O T E S &amp;gt;--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Apply kerning to open the space between the quote mark provided by the Module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value.&lt;br /&gt;
This function will positive kern either single or double quotes:&lt;br /&gt;
	&amp;quot;'Unkerned title with leading and trailing single quote marks'&amp;quot;&lt;br /&gt;
	&amp;quot; 'Kerned title with leading and trailing single quote marks' &amp;quot; (in real life the kerning isn't as wide as this example)&lt;br /&gt;
Double single quotes (italic or bold wikimarkup) are not kerned.&lt;br /&gt;
&lt;br /&gt;
Call this function for chapter titles, for website titles, etc; not for book titles.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function kern_quotes (str)&lt;br /&gt;
	local cap='';&lt;br /&gt;
	local cap2='';&lt;br /&gt;
	&lt;br /&gt;
	cap, cap2 = str:match (&amp;quot;^([\&amp;quot;\'])([^\'].+)&amp;quot;);								-- match leading double or single quote but not double single quotes&lt;br /&gt;
	if is_set (cap) then&lt;br /&gt;
		str = wrap_style ('kern-left', {cap, cap2});&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cap, cap2 = str:match (&amp;quot;^(.+[^\'])([\&amp;quot;\'])$&amp;quot;)&lt;br /&gt;
	if is_set (cap) then&lt;br /&gt;
		str = wrap_style ('kern-right', {cap, cap2});&lt;br /&gt;
	end&lt;br /&gt;
	return str;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; P E N D _ S E P A R A T O R &amp;gt;--------------------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function pend_separator (item, sepc, prepend)&lt;br /&gt;
	if prepend then&lt;br /&gt;
		return is_set (item) and sepc .. ' ' .. item or '';&lt;br /&gt;
	else&lt;br /&gt;
		return is_set (item) and item .. sepc .. ' ' or '';&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S E T _ S E L E C T E D _ M O D U L E S &amp;gt;--------------------------------------&lt;br /&gt;
&lt;br /&gt;
Sets local cfg table to same (live or sandbox) as that used by the other modules.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function set_selected_modules (cfg_table_ptr)&lt;br /&gt;
	cfg = cfg_table_ptr;&lt;br /&gt;
	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E X P O R T S &amp;gt;----------------------------------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	first_set = first_set,														-- exported functions&lt;br /&gt;
	has_accept_as_written = has_accept_as_written,&lt;br /&gt;
	has_invisible_chars = has_invisible_chars,&lt;br /&gt;
	hyphen_to_dash = hyphen_to_dash,&lt;br /&gt;
	in_array = in_array,&lt;br /&gt;
	is_set = is_set,&lt;br /&gt;
	kern_quotes = kern_quotes,&lt;br /&gt;
	make_sep_list = make_sep_list,&lt;br /&gt;
	pend_separator = pend_separator,&lt;br /&gt;
	safe_join = safe_join,&lt;br /&gt;
	substitude = substitude,&lt;br /&gt;
	strip_apostrophe_markup = strip_apostrophe_markup,&lt;br /&gt;
	substitute = substitute,&lt;br /&gt;
	wrap_style = wrap_style,&lt;br /&gt;
	wrap_msg = wrap_msg,&lt;br /&gt;
	&lt;br /&gt;
	set_selected_modules = set_selected_modules&lt;br /&gt;
	}&lt;/div&gt;</summary>
		<author><name>w&gt;Antigng</name></author>
	</entry>
</feed>