<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://www.wikiw.cn/index.php?action=history&amp;feed=atom&amp;title=%E6%A8%A1%E5%9D%97%3ACitation%2FCS1%2FUtilities</id>
	<title>模块:Citation/CS1/Utilities - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://www.wikiw.cn/index.php?action=history&amp;feed=atom&amp;title=%E6%A8%A1%E5%9D%97%3ACitation%2FCS1%2FUtilities"/>
	<link rel="alternate" type="text/html" href="https://www.wikiw.cn/index.php?title=%E6%A8%A1%E5%9D%97:Citation/CS1/Utilities&amp;action=history"/>
	<updated>2026-04-08T18:05:45Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://www.wikiw.cn/index.php?title=%E6%A8%A1%E5%9D%97:Citation/CS1/Utilities&amp;diff=135&amp;oldid=prev</id>
		<title>Admin：​导入1个版本</title>
		<link rel="alternate" type="text/html" href="https://www.wikiw.cn/index.php?title=%E6%A8%A1%E5%9D%97:Citation/CS1/Utilities&amp;diff=135&amp;oldid=prev"/>
		<updated>2025-06-20T16:45:33Z</updated>

		<summary type="html">&lt;p&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-Hans-CN&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;2025年6月21日 (六) 00:45的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;zh-Hans-CN&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>Admin</name></author>
	</entry>
	<entry>
		<id>https://www.wikiw.cn/index.php?title=%E6%A8%A1%E5%9D%97:Citation/CS1/Utilities&amp;diff=134&amp;oldid=prev</id>
		<title>wikiw&gt;Antigng：​ep: 71332844</title>
		<link rel="alternate" type="text/html" href="https://www.wikiw.cn/index.php?title=%E6%A8%A1%E5%9D%97:Citation/CS1/Utilities&amp;diff=134&amp;oldid=prev"/>
		<updated>2022-04-26T16:29:49Z</updated>

		<summary type="html">&lt;p&gt;&lt;a href=&quot;/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;/index.php?title=%E7%89%B9%E6%AE%8A:%E7%BC%96%E8%BE%91%E5%B7%AE%E5%BC%82/71332844&quot; title=&quot;特殊:编辑差异/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( &amp;#039;-&amp;#039;, &amp;#039;–&amp;#039; );&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 &amp;#039;set&amp;#039; 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 == &amp;#039;&amp;#039;);&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 &amp;#039;for _, val in pairs do&amp;#039; 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 (&amp;#039;^%(%((.*)%)%)$&amp;#039;, &amp;#039;%1&amp;#039;); 						-- allows (()) to be an empty set&lt;br /&gt;
	else&lt;br /&gt;
		str, count = str:gsub (&amp;#039;^%(%((.+)%)%)$&amp;#039;, &amp;#039;%1&amp;#039;);&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 &amp;#039;&amp;#039; ... &amp;#039;&amp;#039;&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 &amp;#039;&amp;#039;...&amp;#039;&amp;#039; 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 &amp;#039;&amp;#039; tend to interact&lt;br /&gt;
poorly under Mediawiki&amp;#039;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;#039;&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;#039;&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 (&amp;#039;\n&amp;#039;, &amp;#039; &amp;#039;);&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 &amp;#039;&amp;#039;;&lt;br /&gt;
	elseif in_array (key, cfg.presentation[&amp;#039;_safe_for_italics&amp;#039;]) 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;#039;&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;&amp;#039;&lt;br /&gt;
	&amp;lt;sep_list_pair&amp;gt; - typically &amp;#039;&amp;lt;space&amp;gt;and&amp;lt;space&amp;gt;&amp;#039;&lt;br /&gt;
	&amp;lt;sep_list_end&amp;gt; - typically &amp;#039;&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;and&amp;lt;space&amp;gt;&amp;#039; or &amp;#039;&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;&amp;amp;&amp;lt;space&amp;gt;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
defaults to cfg.presentation[&amp;#039;sep_list&amp;#039;], cfg.presentation[&amp;#039;sep_list_pair&amp;#039;], and cfg.presentation[&amp;#039;sep_list_end&amp;#039;]&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 = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	if not sep_list then														-- set the defaults&lt;br /&gt;
		sep_list = cfg.presentation[&amp;#039;sep_list&amp;#039;];&lt;br /&gt;
		sep_list_pair = cfg.presentation[&amp;#039;sep_list_pair&amp;#039;];&lt;br /&gt;
		sep_list_end = cfg.presentation[&amp;#039;sep_list_end&amp;#039;];&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 = &amp;#039;&amp;#039;;																-- the output string&lt;br /&gt;
	local comp = &amp;#039;&amp;#039;;															-- what does &amp;#039;comp&amp;#039; mean?&lt;br /&gt;
	local end_chr = &amp;#039;&amp;#039;;&lt;br /&gt;
	local trim;&lt;br /&gt;
	for _, value in ipairs( tbl ) do&lt;br /&gt;
		if value == nil then value = &amp;#039;&amp;#039;; end&lt;br /&gt;
		&lt;br /&gt;
		if str == &amp;#039;&amp;#039; 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 ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			if value:sub(1,1) == &amp;#039;&amp;lt;&amp;#039; 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: &amp;#039;First element&amp;#039; .. &amp;#039;sepc next element&amp;#039; .. 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;#039;&amp;quot; then										-- if it might be wikimarkup&lt;br /&gt;
					if str:sub(-3,-1) == duplicate_char .. &amp;quot;&amp;#039;&amp;#039;&amp;quot; then			-- if last three chars of str are sepc&amp;#039;&amp;#039; &lt;br /&gt;
						str = str:sub(1, -4) .. &amp;quot;&amp;#039;&amp;#039;&amp;quot;;							-- remove them and add back &amp;#039;&amp;#039;&lt;br /&gt;
					elseif str:sub(-5,-1) == duplicate_char .. &amp;quot;]]&amp;#039;&amp;#039;&amp;quot; then		-- if last five chars of str are sepc]]&amp;#039;&amp;#039; &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;#039;&amp;#039;&amp;quot; then		-- if last four chars of str are sepc]&amp;#039;&amp;#039; &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;#039;&amp;#039;]&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&amp;#039;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&amp;#039;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;#039;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;) then									-- bold italic (5)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;, &amp;quot;&amp;quot;);							-- remove all instances of it&lt;br /&gt;
		elseif argument:match (&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;) then									-- italic start and end without content (4)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
		elseif argument:match (&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;) then									-- bold (3)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
		elseif argument:match (&amp;quot;%&amp;#039;%&amp;#039;&amp;quot;) then										-- italic (2)&lt;br /&gt;
			argument=argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;&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&amp;#039;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 {{&amp;#039;}} 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 = &amp;#039;&amp;#039;;														-- 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 &amp;#039;nowiki&amp;#039; == capture or &amp;#039;math&amp;#039; == capture or						-- nowiki and math stripmarkers (not an error condition)&lt;br /&gt;
				(&amp;#039;templatestyles&amp;#039; == capture) then	-- templatestyles stripmarker allowed&lt;br /&gt;
					stripmarker = true;											-- set a flag&lt;br /&gt;
			elseif true == stripmarker and &amp;#039;delete&amp;#039; == char then				-- because stripmakers begin and end with the delete char, assume that we&amp;#039;ve found one end of a stripmarker&lt;br /&gt;
				position = nil;													-- unset&lt;br /&gt;
			elseif &amp;#039;apostrophe&amp;#039; == 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, {&amp;#039;zero width joiner&amp;#039;, &amp;#039;zero width space&amp;#039;, &amp;#039;hair space&amp;#039;}) 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 .. &amp;#039; &amp;#039; .. cfg.invisible_chars[i][3] or char;&lt;br /&gt;
				else&lt;br /&gt;
					err_msg = cfg.invisible_chars[i][3] or (char .. &amp;#039; character&amp;#039;);&lt;br /&gt;
				end&lt;br /&gt;
				return {err_msg, wrap_style (&amp;#039;parameter&amp;#039;, 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 &amp;#039;&amp;#039;;&lt;br /&gt;
	elseif in_array (key, cfg.messages[&amp;#039;_safe_for_italics&amp;#039;]) 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&amp;#039;s value.&lt;br /&gt;
This function will positive kern either single or double quotes:&lt;br /&gt;
	&amp;quot;&amp;#039;Unkerned title with leading and trailing single quote marks&amp;#039;&amp;quot;&lt;br /&gt;
	&amp;quot; &amp;#039;Kerned title with leading and trailing single quote marks&amp;#039; &amp;quot; (in real life the kerning isn&amp;#039;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=&amp;#039;&amp;#039;;&lt;br /&gt;
	local cap2=&amp;#039;&amp;#039;;&lt;br /&gt;
	&lt;br /&gt;
	cap, cap2 = str:match (&amp;quot;^([\&amp;quot;\&amp;#039;])([^\&amp;#039;].+)&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 (&amp;#039;kern-left&amp;#039;, {cap, cap2});&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cap, cap2 = str:match (&amp;quot;^(.+[^\&amp;#039;])([\&amp;quot;\&amp;#039;])$&amp;quot;)&lt;br /&gt;
	if is_set (cap) then&lt;br /&gt;
		str = wrap_style (&amp;#039;kern-right&amp;#039;, {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 .. &amp;#039; &amp;#039; .. item or &amp;#039;&amp;#039;;&lt;br /&gt;
	else&lt;br /&gt;
		return is_set (item) and item .. sepc .. &amp;#039; &amp;#039; or &amp;#039;&amp;#039;;&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>wikiw&gt;Antigng</name></author>
	</entry>
</feed>