モジュール:String2

local p = {}
p.trim = function(frame)
	return mw.text.trim(frame.args1 or "")
end
p.sentence = function (frame)
	--  is strip-marker safe, string.lower is not.
	frame.args1 = frame:callParserFunction('lc', frame.args1)
	return p.ucfirst(frame)
end
p.ucfirst = function (frame )
	local s =  mw.text.trim( frame.args1 or "" )
	local s1 = ""
	-- if it's a list chop off and (store as s1) everything up to the first 
	local lipos = mw.ustring.find(s, "" )
	if lipos then
		s1 = mw.ustring.sub(s, 1, lipos + 3)
		s = mw.ustring.sub(s, lipos + 4)
	end
	-- s1 is either "" or the first part of the list markup, so we can continue
	-- and prepend s1 to the returned string
	local letterpos
	if mw.ustring.find(s, "^%%+|^%+%%") then
		-- this is a piped wikilink, so we capitalise the text, not the pipe
		local _
		_, letterpos = mw.ustring.find(s, "|%A*%a") -- find the first letter after the pipe
	else
		letterpos = mw.ustring.find(s, '%a')
	end
	if letterpos then
		local first = mw.ustring.sub(s, 1, letterpos - 1)
		local letter = mw.ustring.sub(s, letterpos, letterpos)
		local rest = mw.ustring.sub(s, letterpos + 1)
		return s1 .. first .. mw.ustring.upper(letter) .. rest
	else
		return s1 .. s
	end
end
p.title = function (frame )
	-- http://grammar.yourdictionary.com/capitalization/rules-for-capitalization-in-titles.html
	-- recommended by The U.S. Government Printing Office Style Manual:
	-- "Capitalize all words in titles of publications and documents,
	-- except a, an, the, at, by, for, in, of, on, to, up, and, as, but, or, and nor."
	local alwayslower = {'a' = 1, 'an' = 1, 'the' = 1,
		'and' = 1, 'but' = 1, 'or' = 1, 'for' = 1,
		'nor' = 1, 'on' = 1, 'in' = 1, 'at' = 1, 'to' = 1,
		'from' = 1, 'by' = 1, 'of' = 1, 'up' = 1 }
	local res = 
	local s =  mw.text.trim( frame.args1 or "" )
	local words = mw.text.split( s, " ")
	for i, s in ipairs(words) do
		--  is strip-marker safe, string.lower is not.
		s = frame:callParserFunction('lc', s)
		if i == 1 or alwayslowers ~= 1 then
			s = mw.getContentLanguage():ucfirst(s)
		end
		wordsi = s
	end
	return table.concat(words, " ")
end
-- findlast finds the last item in a list
-- the first unnamed parameter is the list
-- the second, optional unnamed parameter is the list separator (default = comma space)
-- returns the whole list if separator not found
p.findlast = function(frame)
	local s =  mw.text.trim( frame.args1 or "" )
	local sep = frame.args2 or ""
	if sep == "" then sep = ", " end
	local pattern = ".*" .. sep .. "(.*)"
	local a, b, last = s:find(pattern)
	if a then
		return last
	else
		return s
	end
end
-- stripZeros finds the first number and strips leading zeros (apart from units)
-- e.g "0940" -> "940"; "Year: 0023" -> "Year: 23"; "00.12" -> "0.12"
p.stripZeros = function(frame)
	local s = mw.text.trim(frame.args1 or "")
	local n = tonumber( string.match( s, "%d+" ) ) or ""
	s = string.gsub( s, "%d+", n, 1 )
	return s
end
-- nowiki ensures that a string of text is treated by the MediaWiki software as just a string
-- it takes an unnamed parameter and trims whitespace, then removes any wikicode
p.nowiki = function(frame)
	local str = mw.text.trim(frame.args1 or "")
	return mw.text.nowiki(str)
end
-- split splits text at boundaries specified by separator
-- and returns the chunk for the index idx (starting at 1)
-- #invoke:String2 |split |text |separator |index |true/false
-- #invoke:String2 |split |txt=text |sep=separator |idx=index |plain=true/false
-- if plain is false/no/0 then separator is treated as a Lua pattern - defaults to plain=true
p.split = function(frame)
	local args = frame.args
	if not(args1 or args.txt) then args = frame:getParent().args end
	local txt = args1 or args.txt or ""
	if txt == "" then return nil end
	local sep = (args2 or args.sep or ""):gsub('"', )
	local idx = tonumber(args3 or args.idx) or 1
	local plain = (args4 or args.plain or "true"):sub(1,1)
	plain = (plain ~= "f" and plain ~= "n" and plain ~= "0")
	local splittbl = mw.text.split( txt, sep, plain )
	if idx --------------------------------------------------
Converts a hyphen to a dash under certain conditions.  The hyphen must separate
like items; unlike items are returned unmodified.  These forms are modified:
	letter - letter (A - B)
	digit - digit (4-5)
	digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5)
	letterdigit - letterdigit (A1-A5) (an optional separator between letter and
		digit is supported – a.1-a.5 or a-1-a-5)
	digitletter - digitletter (5a - 5d) (an optional separator between letter and
		digit is supported – 5.a-5.d or 5-a-5-d)
any other forms are returned unmodified.
str may be a comma- or semicolon-separated list
function p.hyphen_to_dash( str, spacing )
	if (str == nil or str == ) then
		return str
	end
	local accept
	str = mw.text.decode(str, true )											-- replace html entities with their characters; semicolon mucks up the text.split
	local out = {}
	local list = mw.text.split (str, '%s*,;%s*')								-- split str at comma or semicolon separators if there are any
	for _, item in ipairs (list) do												-- for each item in the list
		item = mw.text.trim(item)												-- trim whitespace
		item, accept = item:gsub ('^%(%((.+)%)%)$', '%1')
		if accept == 0 and mw.ustring.match (item, '^%w*%.%-?%w+%s*%-–—%s*%w*%.%-?%w+$') then	-- if a hyphenated range or has endash or emdash separators
			if item:match ('^%a+%.%-?%d+%s*%-%s*%a+%.%-?%d+$') or			-- letterdigit hyphen letterdigit (optional separator between letter and digit)
				item:match ('^%d+%.%-?%a+%s*%-%s*%d+%.%-?%a+$') or			-- digitletter hyphen digitletter (optional separator between digit and letter)
				item:match ('^%d+%.%-%d+%s*%-%s*%d+%.%-%d+$') or			-- digit separator digit hyphen digit separator digit
				item:match ('^%d+%s*%-%s*%d+$') or								-- digit hyphen digit
				item:match ('^%a+%s*%-%s*%a+$') then							-- letter hyphen letter
					item = item:gsub ('(%w*%.%-?%w+)%s*%-%s*(%w*%.%-?%w+)', '%1–%2')	-- replace hyphen, remove extraneous space characters
			else
				item = mw.ustring.gsub (item, '%s*–—%s*', '–')				-- for endash or emdash separated ranges, replace em with en, remove extraneous whitespace
			end
		end
		table.insert (out, item)												-- add the (possibly modified) item to the output table
	end
	local temp_str = table.concat (out, ',' .. spacing)							-- concatenate the output table into a comma separated string
	temp_str, accept = temp_str:gsub ('^%(%((.+)%)%)$', '%1')					-- remove accept-this-as-written markup when it wraps all of concatenated out
	if accept ~= 0 then
		temp_str = str:gsub ('^%(%((.+)%)%)$', '%1')							-- when global markup removed, return original str; do it this way to suppress boolean second return value
	end
	return temp_str
end
function p.hyphen2dash( frame )
	local str = frame.args1 or 
	local spacing = frame.args2 or ' ' -- space is part of the standard separator for normal spacing (but in conjunction with templates r/rp/ran we may need a narrower spacing
	return p.hyphen_to_dash(str, spacing)
end
-- Similar to Module:String#endswith
function p.startswith(frame)
	return (frame.args1:sub(1, frame.args2:len()) == frame.args2) and 'yes' or 
end
return p