เอกสารการใช้งานสำหรับมอดูลนี้อาจสร้างขึ้นที่ มอดูล:FormatProofread/doc

local p = {}

--[=[
(example of input text)

มาตรา ๕  ให้รัฐมนตรีว่าการกระทรวงมหาดไทยรักษาการตามพระราชบัญญัตินี้ และให้...

กฎกระทรวงนั้น เมื่อได้ประกาศในราชกิจจานุเบกษาแล้ว ให้ใช้บังคับได้

 

ลักษณะ ๑

การใช้รถ

                  

 

หมวด ๑

ลักษณะของรถที่ใช้ในทาง

                  

 

มาตรา ๖  ห้ามมิให้ผู้ใดนำรถที่มีสภาพไม่มั่นคงแข็งแรง หรืออาจเกิดอันตราย หรืออาจทำให้...

รถที่ใช้ในทางเดินรถ ผู้ขับขี่ต้องจัดให้มีเครื่องยนตร์ เครื่องอุปกรณ์และหรือส่วนควบที่...

สภาพของรถที่อาจทำให้เสื่อมเสียสุขภาพอนามัยตามวรรคหนึ่งและวิธีการทดสอบ ให้เป็นไปตามหลักเกณฑ์และวิธีการที่กำหนดในกฎกระทรวง

...
...

มาตรา ๔๙  เมื่อได้รับสัญญาณขอแซงขึ้นหน้าจากรถคันที่อยู่ข้างหลัง ผู้ขับขี่ซึ่ง...

 

หมวด ๓

การออกรถ การเลี้ยวรถและการกลับรถ

                  

 

มาตรา ๕๐  การขับรถออกจากที่จอด ถ้ามีรถจอดหรือมีสิ่งกีดขวางอยู่ข้างหน้า ผู้ขับขี่ต้อง...

 

มาตรา ๕๑  การเลี้ยวรถ ให้ปฏิบัติดังนี้

(๑) ถ้าจะเลี้ยวซ้าย

(ก) ในกรณีที่ไม่ได้แบ่งช่องเดินรถไว้ ให้ผู้ขับขี่ขับรถชิดทางเดินรถด้านซ้าย

(ข) ในกรณีที่มีการแบ่งช่องเดินรถไว้ และมีเครื่องหมายจราจรแสดงให้เลี้ยวซ้ายได้ ให้ผู้ขับขี่...

(ค) ในกรณีที่มีช่องเดินรถประจำทางอยู่ทางเดินรถด้านซ้ายสุด ให้ผู้ขับขี่...

(๒) ถ้าจะเลี้ยวขวา

(ก) สำหรับทางเดินรถที่ไม่ได้แบ่งช่องเดินรถไว้ ให้ผู้ขับขี่...

...

(๓) ถ้าจะเลี้ยวอ้อมวงเวียนหรือเกาะที่สร้างไว้ ให้ผู้ขับขี่ขับรถอ้อมไปทางซ้ายของวงเวียนหรือเกาะนั้น

ในกรณีตาม (๑) และ (๒) ผู้ขับขี่ต้อง...

 

มาตรา ๕๒  ในทางเดินรถที่สวนกันได้ ห้ามมิให้ผู้ขับขี่กลับรถในเมื่อมีรถอื่นสวน หรือตามมาในระยะไม่น้อยกว่าหนึ่งร้อยห้าสิบเมตร

ถ้าการกลับรถในทางเดินรถที่สวนกันได้จะเป็นการกีดขวางการจราจร ห้ามมิให้ผู้ขับขี่กลับรถในทางเดินรถนั้น

--]=]

--[=[
   Example:
      To expand "abc{{t1|a1|b1|c1}}def{{t2|a2|p2=b2}}{{t3}}xyz" do the following,
         expandTemplates(mw.getCurrentFrame(), {
            'abc',
            { 't1', {'a1', 'b1', 'c1'} },
            'def',
            { 't2', {'a2', ['p2']='b2'} },
            { 't3', {} },
            'xyz',
         } )
--]=]
local function expandTemplates(frame, t)
	local r = ''
	for i, v in ipairs(t) do
		if type(v)=='table' then
			r = r..frame:expandTemplate{title=v[1], args=v[2]}
		else
			r = r..v
		end
	end
	return r
end

-- p == { multiline, pattern, section name, number of lines following matched line,
--    function (matchResult, { line1, line2, ... }, state, frame)
-- }
local function multiline(v, p, state, frame)
	--if state.section ~= nil then
	--	if state.section ~= p[3] then return false end
	--	state.section = nil; return p[5](state.sectionVal)
	--end
	--if state.section == p[3] then state.section = nil; return p[5](state.sectionVal, v, frame) end
	if state.section == p[3] then
		table.insert(state.sectionLine, v)
		if #state.sectionLine < p[4] then return nil end
		state.section = nil; return p[5](state.sectionVal, state.sectionLine, state, frame)
	end
	if state.section ~= nil then return false end
	--local c = gsub(v, p, state) -- result is string or false
	--if c then return nil end
	--return c
	--local c = {mw.ustring.match(v, p[2])}
	-- "not x" is faster than "x == nil"
	----if c[1] == nil then return false end
	----state.section = p[3]; state.sectionVal = c; state.sectionLine = {}; return nil
	--if c[1] then
	--	state.section = p[3]; state.sectionVal = c; state.sectionLine = {}; return nil
	--end
	if type(p[2]) ~= 'table' then p[2] = { p[2] } end
	for _, p2 in ipairs(p[2]) do
		-- c[1] is string or nil
		local c = {mw.ustring.match(v, p2)}
		if c[1] then
			state.section = p[3]; state.sectionVal = c; state.sectionLine = {}
			state.pattern = pat
			return nil
		end
	end
	return false
end

-- This is deprecated, as it seem too complex
-- p == { section, pattern, section name, function (matchResult, v, state, frame) }
local function section(v, p, state, frame)
	return multiline(v, { p[1], p[2], p[3], 1, function (matchResult, line, state, frame)
		return p[4](matchResult, line[1], state, frame)
	end }, state, frame)
end

-- p == { gsub, mw.ustring.gsub's 2nd, func(state, frame, gsub's captured var ...), mw.ustring.gsub's 4th parameter }
local function gsub(v, p, state, frame)
	if type(p[2]) ~= 'table' then p[2] = { p[2] } end
	for _, p2 in ipairs(p[2]) do
		state.pattern = p2
		--local r, c = mw.ustring.gsub(v, p2, p[3], p[4])
		local r, c = mw.ustring.gsub(v, p2, function (...) return p[3](state, frame, ...) end, p[4])
		--return r, c > 0
		if c > 0 then return r end
	end
	return false
end

-- p == { del, pattern }
local function del(v, p, state, frame)
	if mw.ustring.match(v, p[2]) then return nil end
	return false
end

-- For passed as named template parameter that is going to be preprocessed.
-- Since input text is assumed to has already been preprocessed, so '{', '}', and '<' are escaped
-- to prevent them to be preprocessed.  '[' is escaped to handle the case like '{{t1|a1=[[a}}
--
--    Example: frame:preprocess('{{t1|a1='..escapeNamedTemplateParameter(s)..'}}')
--
-- Note: This does not convert '=' to '{{=}}'
--
local function escapeNamedTemplateParameter(s)
	return s:gsub('[{}<[]', '%1<!---->'):gsub('|', '{{!}}')
end
local escN = escapeNamedTemplateParameter

-- Suitable for passed as unnamed template parameter that is going to be preprocessed,
-- as it also convert '=' to '{{=}}'
--
--    Example: frame:preprocess('{{t1|'..escapeTemplateParameter(s)..'}}')
--
local function escapeTemplateParameter(s)
	return s:gsub('[{}<[]', '%1<!---->'):gsub('[|=]', {['|']='{{!}}', ['=']='{{=}}'})
end
local esc = escapeTemplateParameter

local pat = {

['ราชกิจจานุเบกษา']={
	['กฎหมาย']={

		--[=[
		-- in: ลักษณะ ๑

		       การใช้รถ
		-- out1: {{ก|{{รมมจ|ลักษณะ ๑|การใช้รถ}}}}
		         {{เส้นตรง|7em}}
		-- out2: {{ก|{{รมมจ|ลักษณะ ๑|{{u|การใช้รถ}}}}}}
		--
		-- in: หมวด ๑

		       ลักษณะของรถที่ใช้ในทาง
		-- out1: {{กม|หม|๑|ลักษณะของรถที่ใช้ในทาง}}
		         {{เส้นตรง|7em}}
		-- out2: {{กม|หม|๑|{{u|ลักษณะของรถที่ใช้ในทาง}}}}
		--]=]
		--[=[
		{ section, {
				'^(\n?)(ลักษณะ) +([๐-๙]+) *\n?$',
				'^(\n?)(หมวด) +([๐-๙]+) *\n?$',
			}, 'section', function (match, v, state, frame)
				local enclose = state.p[5][match[2]]
				if frame.args.u:len()>0 then
					----v = '{{ก|{{รมมจ|ลักษณะ '..match[3]..'|'..mw.text.tag('u', {}, esc(v))..'}}}}'
					--v = '{{ก|{{รมมจ|ลักษณะ '..match[3]..'|{{u|'..esc(v)..'}}}}}}'
					v = enclose[1]..match[3]..'|{{u|'..esc(v)..'}}'..enclose[2]
				else
					--v = '{{ก|{{รมมจ|ลักษณะ '..match[2]..'|'..esc(v)..'}}}}\n{{เส้นตรง|7em}}'
					v = enclose[1]..match[3]..'|'..esc(v)..enclose[2]..'\n{{เส้นตรง|7em}}'
				end
				return match[1]..frame:preprocess(v)
			end, {
				-- this table can be accessed as state.p[5]
				['ลักษณะ'] = { '{{ก|{{รมมจ|ลักษณะ ', '}}}}' },
				['หมวด'] = { '{{กม|หม|', '}}' },
			}
		},
		--]=]
		{ multiline, {
				'^(\n?)(ลักษณะ) +([๐-๙]+) *\n?$',
				'^(\n?)(หมวด) +([๐-๙]+) *\n?$',
			}, 'section', 1, function (match, line, state, frame)
				local enclose = state.p[6][match[2]]
				if frame.args.u:len()>0 then
					-- result of tag "<u>" processing showing that none of these functions do escape
					-- the '<' nor '>' character,
					--    mw.logObject(mw.getCurrentFrame():extensionTag('u', 'z</u>z2<u>z3'))
					--    "<u>z</u>z2<u>z3</u>"
					--    mw.logObject(mw.getCurrentFrame():callParserFunction('#tag:u', 'z</u>z2<u>z3'))
					--    "<u>z</u>z2<u>z3</u>"
					--    mw.logObject(mw.getCurrentFrame():preprocess('{{#tag:u|z</u>z2<u>z3}}'))
					--    "<u>z</u>z2<u>z3</u>"
					--    mw.logObject(mw.text.tag('u', {}, 'z</u>z2<u>z3'))
					--    "<u>z</u>z2<u>z3</u>"
					----line = '{{ก|{{รมมจ|ลักษณะ '..match[3]..'|'..mw.text.tag('u', {}, esc(line[1]))..'}}}}'
					--line = '{{ก|{{รมมจ|ลักษณะ '..match[3]..'|{{u|'..esc(line[1])..'}}}}}}'
					line = enclose[1]..match[3]..'|{{u|'..esc(line[1])..'}}'..enclose[2]
				else
					--line = '{{ก|{{รมมจ|ลักษณะ '..match[2]..'|'..esc(line[1])..'}}}}\n{{เส้นตรง|7em}}'
					line = enclose[1]..match[3]..'|'..esc(line[1])..enclose[2]..'\n{{เส้นตรง|7em}}'
				end
				return match[1]..frame:preprocess(line)
			end, {
				-- this table can be accessed as state.p[6]
				['ลักษณะ'] = { '{{ก|{{รมมจ|ลักษณะ ', '}}}}' },
				['หมวด'] = { '{{กม|{{{หม|หม1}}}|', '}}' },
			}
		},

		--[=[
		-- in: ผู้รับสนองพระบรมราชโองการ

		       พลเอก เกรียงศักดิ์  ชมะนันทน์

		       นายกรัฐมนตรี
		-- out: 
		        {{กซ|{{รมมจ|ผู้รับสนองพระบรมราชโองการ|พลเอก เกรียงศักดิ์  ชมะนันทน์|นายกรัฐมนตรี}}|center}}
		--
		-- in: ผู้รับสนองพระราชโองการ

		       พลเอก ประยุทธ์ จันทร์โอชา

		       นายกรัฐมนตรี
		-- out: 
		        {{รมมจ|ผู้รับสนองพระราชโองการ|พลเอก ประยุทธ์ จันทร์โอชา|นายกรัฐมนตรี}}|center}}
		--]=]
		{ multiline, {
				'^(\n?)(ผู้รับสนองพระบรมราชโองการ)\n?$',
				'^(\n?)(ผู้รับสนองพระราชโองการ)\n?$',
			}, 'ผู้รับสนองพระบรมราชโองการ', 2,
			function (match, line, state, frame)
				local p = ''; if state.i > 1 then p = '\n' end
				return p..frame:preprocess(
					'{{กซ|{{รมมจ|'..match[2]..'|'..esc(line[1])..'|'..esc(line[2])..'}}|center}}'
				)
			end
		},

		-- in: มาตรา ๕๑  การเลี้ยวรถ ให้ปฏิบัติดังนี้
		-- out: {{กม|ม|๕๑}}การเลี้ยวรถ ให้ปฏิบัติดังนี้
		-- * not use '^(\n*)...', since there never be more than one consecutive '\n'
		{ gsub, '^(\n?)มาตรา +([๐-๙]+) +', function (state, frame, p, n)
			-- expandTemplate() should be more efficient than preprocess()
			-- however from experiment in Module:User:Ans/PerformanceTest,
			-- * preprocess() with nowiki() is 4 times faster than expandTemplate(),
			-- * preprocess() is 4 times faster than preprocess() witth nowiki()
			--return p..frame:preprocess('{{กม|ม|'..n..'}}')
			--return p..frame:preprocess('{{กม|'..esc(frame.args['ม'])..'|'..n..'}}')
			return p..frame:preprocess('{{กม|{{{ม|ม1}}}|'..n..'}}')
			--return p..mw.getCurrentFrame():expandTemplate{title='กม', args={'ม', n}}
		end, 1 },

		--[=[
		--
		-- ไม่รวมจัดรูปแบบพวกมาตราแก้ไขเพิ่มเติม เช่น "มาตรา ๒๘/๑๕" หรือ "มาตรา ๒๙ ทวิ"
		-- เพราะ มาตราพวกนี้ใน ราชกิจจานุเบกษา จะอยู่ในเครื่องหมายคำพูดอีกที เช่น
		--
		--    มาตรา ๔ ให้เพิ่มความต่อไปนี้เป็นมาตรา ๓๒/๑ มาตรา ๓๒/๒ และมาตรา ๓๒/๓ แห่งพระราชบัญญัติลิขสิทธิ์ พ.ศ. ๒๕๓๗
		--    "มาตรา ๓๒/๑ การจำหน่ายต้นฉบับหรือสำเนางานอันมีลิขสิทธิ์โดย...
		--    มาตรา ๓๒/๒ การกระทำแก่งานอันมีลิขสิทธิ์ที่ทำหรือได้มาโดยชอบ..."
		--
		-- แต่หากต้องการจัดรูปแบบมาตราประเภท "มาตรา ๒๘/๑๕" เข้าไปด้วย ให้ uncomment code ด้านล่างนี้
		-- (ส่วนมาตราประเภท "มาตรา ๒๙ ทวิ" ยังจัดรูปแบบอัตโนมัติไม่ได้)
		--]=]
		-- in: มาตรา ๒๘/๑๕ ...
		-- out: {{กม|ม|๒๘/๑๕}}...
		--{ gsub, '^(\n?)มาตรา +([๐-๙]+/[๐-๙]+) +', function (state, frame, p, n)
		--	return p..frame:preprocess('{{กม|{{{ม|ม1}}}|'..n..'}}')
		--end, 1 },

		-- in: (๑) ถ้าจะเลี้ยวซ้าย
		-- out: {{กม|วล|๑}}ถ้าจะเลี้ยวซ้าย
		{ gsub, '^(\n?)%(([๐-๙]+)%) *', function (state, frame, p, n)
			-- expandTemplate() should be more efficient than preprocess()
			-- however from experiment in Module:User:Ans/PerformanceTest,
			-- * preprocess() with nowiki() is 4 times faster than expandTemplate(),
			-- * preprocess() is 4 times faster than preprocess() witth nowiki()
			return p..frame:preprocess('{{กม|วล|'..n..'}}')
			--return p..mw.getCurrentFrame():expandTemplate{title='กม', args={'วล', n}}
		end, 1 },

		-- in: (๑/๑) ...
		-- out: {{กม|วล|๑/๑}}...
		--{ gsub, '^(\n?)%(([๐-๙]+/[๐-๙]+)%) *', function (state, frame, p, n)
		--	return p..frame:expandTemplate{title='กม', args={'วล', n}}
		--end, 1},

		-- in: (ก) ในกรณีที่ไม่ได้แบ่งช่องเดินรถไว้ ให้ผู้ขับขี่ขับรถชิดทางเดินรถด้านซ้าย
		-- out: {{ชว}}{{กม|วล|ก}}ในกรณีที่ไม่ได้แบ่งช่องเดินรถไว้ ให้ผู้ขับขี่ขับรถชิดทางเดินรถด้านซ้าย
		{ gsub, '^(\n?)%(([ก-ฮ]+)%) *', function (state, frame, p, n)
			-- expandTemplate() should be more efficient than preprocess(),
			-- however from experiment in Module:User:Ans/PerformanceTest,
			-- * preprocess() with nowiki() is 10 times faster than expandTemplate(),
			-- * preprocess() is 2 times faster than preprocess() witth nowiki()
			return p..frame:preprocess('{{ชว}}{{กม|วล|'..n..'}}')
			--return p..mw.getCurrentFrame():preprocess('{{ชว}}{{กม|วล|'..mw.text.nowiki(n)..'}}')
			--return p..
			--	mw.getCurrentFrame():expandTemplate{title='ชว', args={}}..
			--	mw.getCurrentFrame():expandTemplate{title='กม', args={'วล', n}}
			--return p..
			--	expandTemplates(mw.getCurrentFrame(), { {'ชว',{}}, { 'กม',{'วล', n}} })
		end, 1 },

		-- in: หมายเหตุ:- เหตุผลในการประกาศใช้พระราชบัญญัติฉบับนี้ คือ ...
		-- out: 
		        ----{{กม|มห0|เหตุผลในการประกาศใช้พระราชบัญญัติฉบับนี้ คือ ...}}
		--
		-- in: หมายเหตุ :- เหตุผลในการประกาศใช้พระราชบัญญัติฉบับนี้ คือ ...
		-- out: 
		        ----{{กม|มห|เหตุผลในการประกาศใช้พระราชบัญญัติฉบับนี้ คือ ...}}
		{ gsub, '^(\n?)หมายเหตุ( ?):%- (.*)$', function (state, frame, p, z, s)
			if state.i > 1 then p = '\n----' else p = '' end
			if z == '' then z = '0' else z = '' end
			return p..frame:preprocess('{{กม|มห'..z..'|'..esc(s)..'}}')
		end, 1 },

		-- remove blank line
		--{ del, '^\n? *\n?$' },
		--{ del, '^\n?[ \n]*\n?$' },
		{ del, '^[ \n]*$' },

	}
}

}

--[[
------------------------------------------------------------------------------------
-- ipairsAtOffset

-- This is an iterator for arrays. It can be used like ipairs, but with
-- specified i as first index to iterate. i is an offset from 1
--
------------------------------------------------------------------------------------
--]]
local function ipairsAtOffset(t, i)
	local f, s, i0 = ipairs(t)
	return f, s, i0+i
end

local function format(pat, frame, iterFunc, iterStatic, iterVar)
	local r, state = {}, {}
	-- not work, if "..." is referenced, arg will be nil
	--local text; for i, v in ... do arg[3], text = i, v; break end
	local text
	for i, v in iterFunc, iterStatic, iterVar do iterVar, text = i, v; break end
	local patIter = {ipairs(pat)}
	for i, v in ipairs(mw.text.split(text, '\n\n', true)) do
		state.i = i; for _, p in unpack(patIter) do
			state.p = p
			--local c = p[1](v, p, state, frame, iterFunc, iterStatic, iterVar)
			local r, c = pcall(p[1], v, p, state, frame, iterFunc, iterStatic, iterVar)
			-- "r == false" is 65-75% slower than "not r" (tested by [[Module:User:Ans/PerformanceTest]]
			if not r then v = frame:preprocess('{{error|'..esc(c)..'}}')..v;
				mw.logObject(c, 'c'); mw.logObject(_, '_'); mw.logObject(p, 'p')
			break end
			-- result could be,
			-- * string: insert entry
			-- * nil: skip entry
			-- * false: not match
			--if c then v = c; break end
			--if c == nil then v = c; break end
			if c ~= false then v = c; break end
		end
		if v then table.insert(r, v) end
	end
	return table.concat(r, '\n\n')
end

p['ราชกิจจานุเบกษา'] = function (frame)
	local args = frame.args
	-- these cannot be used to change result of frame:preprocess('{{{u}}}') nor
	-- frame:expandTemplate {title=..., args=frame.args}
	if not args.u then args.u = '' end
	if not args['ม'] then args['ม'] = 'ม1' end
	if not args['หม'] then args['หม'] = 'หม1' end
	--local r = mw.text.split(frame.args[1], '\n\n', true)
	--for i, v in ipairs(r) do
	--	--r[i] = mw.ustring.gsub(v, '^(\n*)มาตรา +([๐-๙]+) +', frame:preprocess('%1{{กม|ม|%2}}'), 1)
	--	--r[i] = frame:preprocess(mw.ustring.gsub(v, '^(\n*)มาตรา +([๐-๙]+) +', '%1{{กม|ม|%2}}', 1))
	--	--r[i] = mw.ustring.gsub(v, '^(\n*)มาตรา +([๐-๙]+) +', function (p, n)
	--	--	--return p..frame:preprocess('{{กม|ม|'..n..'}}')
	--	--	return p..frame:expandTemplate{title='กม', args={'ม', n}}
	--	--end, 1)
	--	for j, p in ipairs(pat['ราชกิจจานุเบกษา']['กฎหมาย']) do
	--		local c;
	--		r[i], c = mw.ustring.gsub(v, p[1], p[2], p[3])
	--		if c > 0 then break end
	--	end
	--end
	--return table.concat(r, '\n\n')
	return format(pat['ราชกิจจานุเบกษา'][frame.args[1]], frame, ipairsAtOffset(frame.args, 1))
end

return p