模块:Wikitable.lua:修订间差异

来自「荏苒之境」
创建空白页面
 
无编辑摘要
第1行: 第1行:
local unpack = unpack or table.unpack


local BYTE_ENTER = string.byte('\r')
local BYTE_NEWLINE = string.byte('\n')
local BYTE_OPEN_CURLY = string.byte('{')
local BYTE_CLOSE_CURLY = string.byte('}')
local BYTE_SEPARATOR = string.byte('|')
local BYTE_EXCLAMATION = string.byte('!')
local BYTE_MINUS = string.byte('-')
local wikitable = {}
local function skip_to_next_line(str, pos)
    while true do
        local b = string.byte(str, pos)
        if b == BYTE_NEWLINE or b == BYTE_ENTER then
            return pos + 1
        elseif b == nil then
            return nil
        end
        pos = pos + 1
    end
end
local function find_character(str, pos, cbyte)
    while true do
        local b = string.byte(str, pos)
        if b == cbyte then
            return pos
        elseif b == nil then
            return nil
        end
        pos = pos + 1
    end
end
local function find_table_start(str, pos)
    pos = find_character(str, pos, BYTE_OPEN_CURLY)
    if pos == nil then return nil end
    pos = find_character(str, pos, BYTE_SEPARATOR)
    if pos == nil then return nil end
    return pos + 1
end
local function parse_cell(str, pos)
    local head = string.byte(str, pos)
    pos = pos + 1
    local bytes = {}
    while true do
        local b = string.byte(str, pos)
        if b == BYTE_NEWLINE then
            pos = pos + 1
            break
        elseif b == nil then
            pos = nil
            break
        end
        if b ~= BYTE_ENTER then
            bytes[#bytes+1] = b
        end
        pos = pos + 1
    end
    if head == BYTE_EXCLAMATION then
        return pos, "header", string.char(unpack(bytes))
    elseif head == BYTE_SEPARATOR then
        local fst_byte = bytes[1]
        if fst_byte == BYTE_MINUS then
            return pos, "row_end"
        elseif fst_byte == BYTE_CLOSE_CURLY then
            return pos, "table_end"
        else
            return pos, "text", string.char(unpack(bytes))
        end
    end
end
wikitable.parse = function(str)
    local header = {}
    local rows = { header = header }
    local curr_row
    local pos = find_table_start(str, 1)
    if pos == nil then return rows end
    pos = skip_to_next_line(str, pos)
    local cell_type, cell_content
    while pos ~= nil do
        pos, cell_type, cell_content = parse_cell(str, pos)
        if cell_type == "header" then
            header[#header+1] = cell_content
        elseif cell_type == "row_end"
            or cell_type == "table_end" then
            if curr_row then
                rows[#rows+1] = curr_row
            end
            curr_row = {}
            if cell_type == "table_end" then
                break
            end
        else
            if curr_row == nil then
                curr_row = {}
            end
            curr_row[#curr_row+1] = cell_content
        end
    end
    return rows
end
return wikitable

2025年8月6日 (三) 00:31的版本

此模块的文档可以在模块:Wikitable.lua/doc创建

local unpack = unpack or table.unpack

local BYTE_ENTER = string.byte('\r')
local BYTE_NEWLINE = string.byte('\n')
local BYTE_OPEN_CURLY = string.byte('{')
local BYTE_CLOSE_CURLY = string.byte('}')
local BYTE_SEPARATOR = string.byte('|')
local BYTE_EXCLAMATION = string.byte('!')
local BYTE_MINUS = string.byte('-')

local wikitable = {}

local function skip_to_next_line(str, pos)
    while true do
        local b = string.byte(str, pos)
        if b == BYTE_NEWLINE or b == BYTE_ENTER then
            return pos + 1
        elseif b == nil then
            return nil
        end
        pos = pos + 1
    end
end

local function find_character(str, pos, cbyte)
    while true do
        local b = string.byte(str, pos)
        if b == cbyte then
            return pos
        elseif b == nil then
            return nil
        end
        pos = pos + 1
    end
end

local function find_table_start(str, pos)
    pos = find_character(str, pos, BYTE_OPEN_CURLY)
    if pos == nil then return nil end
    pos = find_character(str, pos, BYTE_SEPARATOR)
    if pos == nil then return nil end
    return pos + 1
end

local function parse_cell(str, pos)
    local head = string.byte(str, pos)
    pos = pos + 1

    local bytes = {}
    while true do
        local b = string.byte(str, pos)
        if b == BYTE_NEWLINE then
            pos = pos + 1
            break
        elseif b == nil then
            pos = nil
            break
        end
        if b ~= BYTE_ENTER then
            bytes[#bytes+1] = b
        end
        pos = pos + 1
    end

    if head == BYTE_EXCLAMATION then
        return pos, "header", string.char(unpack(bytes))
    elseif head == BYTE_SEPARATOR then
        local fst_byte = bytes[1]
        if fst_byte == BYTE_MINUS then
            return pos, "row_end"
        elseif fst_byte == BYTE_CLOSE_CURLY then
            return pos, "table_end"
        else
            return pos, "text", string.char(unpack(bytes))
        end
    end
end

wikitable.parse = function(str)
    local header = {}
    local rows = { header = header }
    local curr_row

    local pos = find_table_start(str, 1)
    if pos == nil then return rows end
    pos = skip_to_next_line(str, pos)

    local cell_type, cell_content

    while pos ~= nil do
        pos, cell_type, cell_content = parse_cell(str, pos)
        if cell_type == "header" then
            header[#header+1] = cell_content
        elseif cell_type == "row_end"
            or cell_type == "table_end" then
            if curr_row then
                rows[#rows+1] = curr_row
            end
            curr_row = {}
            if cell_type == "table_end" then
                break
            end
        else
            if curr_row == nil then
                curr_row = {}
            end
            curr_row[#curr_row+1] = cell_content
        end
    end

    return rows
end

return wikitable