ข้ามไปเนื้อหา

มอดูล:string/gline

จาก วิกิพจนานุกรม พจนานุกรมเสรี

local error = error
local find = string.find
local gmatch = string.gmatch
local sub = string.sub

--[==[
Iterates over the lines in a string, treating {"\n"}, {"\r"} and {"\r\n"} as new lines.

The optional {skip} parameter determines whether certain lines are skipped:
* {NONE}: none (default).
* {EMPTY}: empty lines: lines with a length of 0, consisting of no characters.
* {BLANK}: blank lines: empty lines and lines which only consist of whitespace characters.]==]
return function(str, skip)
	-- Use gmatch() for EMPTY and BLANK, for speed.
	if skip == "EMPTY" then
		return gmatch(str, "[^\n\r]+")
	elseif skip == "BLANK" then
		return gmatch(str, "[^\n\r]-%S[^\n\r]*")
	end
	local start, pattern, plain, final = 1
	if not (skip == nil or skip == "NONE") then
		error("bad argument #2 to 'iterate_lines' (expected NONE, EMPTY or BLANK)", 2)
	-- If the string contains \n and \r, use a comprehensive pattern; otherwise,
	-- just look for the single characters with a plain match, which is much
	-- faster. \r is very unlikely to be present, so look for it first.
	elseif not find(str, "\r", nil, true) then
		pattern, plain = "\n", true
	elseif not find(str, "\n", nil, true) then
		pattern, plain = "\r", true
	else
		pattern = "([\n\r]\n?)"
	end
	return function()
		if final then
			return
		end
		local pos1, pos2, newline = find(str, pattern, start, plain)
		if not pos1 then
			final = true
			return sub(str, start)
		end
		local line = sub(str, start, pos1 - 1)
		-- Advance `start` past `newline`. The comprehensive pattern will also
		-- capture \n\n as a single match, so only advance past the first \n if
		-- that happens; however, \r\n should be treated as a single new line.
		start = newline == "\n\n" and pos2 or pos2 + 1
		return line
	end
end