Module:Sandbox/Ahecht/coords

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search
p = {}

function p._split(text)
	text = mw.ustring.gsub(mw.text.trim(text), "[*′″]", {['*'] = '°', ['′'] = "'", ['″'] = '"'})
	local lat, long
	local regexes = {
		"^([+%-%d.°'\"NS%s]+),%s*([+%-%d.°'\"EW%s]+)$",							--split by commas
		"^([+%-%d.°'\"%s]+[NS])%s*([+%-%d.°'\"%s]+[EW])$",						--split by N/S
		"^([+%-%d.°'%s]+\")%s*([+%-%d.°'%s]+\")$",								--split by "
		"^([+%-%d.°%s]+')%s*([+%-%d.°%s]+')$",									--split by '
		"^([+%-%d.%s]+°)%s*([+%-%d.%s]+°)$",									--split by °
		"^([+%-%d.]+)%s*([+%-%d.]+)$"											--split by space
	}
	for _, regex in ipairs(regexes) do
		lat, long = string.match(text, regex)
		if lat and long then return {mw.text.trim(lat), mw.text.trim(long)} end
	end
end

function p._parse(text)
	local parts = p._split(text)
	local errmsg = '<strong class="error">Unable to parse "' .. text .. '" as coordinates.</strong>'
	if not parts then return errmsg	end
	local coords = {}
	for k, v in ipairs(parts) do
		local count, number
		-- Convert N, S, E, and W
		v, count = string.gsub(v, '(%s*[SW])$', '')
		if count > 0 and v:sub(1,1) ~= '-' then
			v = '-' .. v
		else
			v = string.gsub(v, '(%s*[NE])$', '')
		end
		-- attempt to convert text to number
		coords[k] = tonumber(v)
		-- attempt to convert dms to decimal
		if not coords[k] and string.match(v, "[°'\"]") then
			number = tonumber(string.match(v, "^[^'\"]+'%s*([%d.]+)%s*\"[^'\"]*$"))
			if number and tonumber(number) then
				coords[k] = (coords[k] or 0) + (number/3600)
			end
			number = tonumber(string.match(v, "^[^°']+°%s*([%d.]+)%s*'[^°']*$"))
			if number and tonumber(number) then
				coords[k] = (coords[k] or 0) + (number/60)
			end
			number = tonumber(string.match(v, "^%s*([+%-%d.]+)%s*°[^°]*$"))
			if number and tonumber(number) then
				coords[k] = (coords[k] or 0) + number
			end
		end
		if not coords[k] then return errmsg	end
	end
	return coords
end

function p.parse(frame)
	parsed = p._parse(frame.args[1])
	if not parsed then
		return '<strong class="error">Unable to parse "' .. (frame.args[1] or '') .. '" as coordinates.</strong>'
	end
	if parsed[1] < 0 then
		parsed[1] = (-1 * parsed[1]) .. "_S"
	else
		parsed[1] = parsed[1] .. "_N"
	end
	if parsed[2] < 0 then
		parsed[2] = (-1 * parsed[2]) .. "_W"
	else
		parsed[2] = parsed[2] .. "_E"
	end
	return parsed[1] .. '_' .. parsed[2]
end

return p