Ace Attorney Wiki
No edit summary
(putting multiple splits into p.SplitTable)
(27 intermediate revisions by the same user not shown)
Line 42: Line 42:
 
end
 
end
   
local function columnPositions(rowText)
+
local function findFirstRow(wikitable, str)
-- Gets the positions of instances of the column delimiter | in a table row's wikitext.
+
-- Finds the first row in the wikitable containing the requested string str.
 
local rowP = rowPositions(wikitable)
return delimiterPositions(rowtext, "|", "$")[1]
 
 
local pos, _ = string.find(wikitable, str)
end
 
 
local i = 1
 
 
while rowP[i] < pos do
local function columns(rowtext)
 
-- Gets the number of columns in a table's wikitext.
+
i = i + 1
return delimiterPositions(rowtext, "|", "$")[2]
 
end
 
 
local function findFirstRow(wikitable, str, col)
 
newCol = col or 0
 
rowP = rowPositions(wikitable)
 
pos = 1
 
while string.find(string.sub(wikitable, pos), str) ~= nil do
 
p, _ = string.find(string.sub(wikitable, pos), str)
 
for n = 1, rows(wikitable) do
 
if rowP[n] > p then
 
candidate = n - 1
 
if newCol == 0 then
 
return candidate
 
else
 
colP = columnPositions(fetchOneRow(wikitable, candidate))
 
nextColP = colP[newCol + 1] or columns(fetchOneRow(wikitable, candidate))
 
if colP[newCol] < p and colP[newCol + 1] > p then
 
return candidate
 
end
 
end
 
pos = rowP[n]
 
break
 
end
 
end
 
 
end
 
end
  +
return i - 1
 
end
 
end
   
 
local function columns(wikitable)
 
local function columns(wikitable)
 
-- Gets the names of the columns.
 
-- Gets the names of the columns.
names = {}
+
local names = {}
posTable = delimiterPositions(wikitable, "!", "|-")
+
local posTable = delimiterPositions(wikitable, "!", "|-")
 
for n = 1, posTable[2] do
 
for n = 1, posTable[2] do
 
names[n] = string.sub(wikitable, posTable[1][n] + 1, posTable[1][n + 1] - 1)
 
names[n] = string.sub(wikitable, posTable[1][n] + 1, posTable[1][n + 1] - 1)
Line 87: Line 63:
 
end
 
end
   
function p.partialTable(frame)
+
function p.tableRange(frame)
-- Constructs a subtable of the given table containing the specified range of rows. For example, {{#invoke:table|partialTable|(table)|3|7}} produces a table using rows 3-7 of the original table.
+
-- Constructs a subtable of the given table containing the specified range of rows.
  +
-- {{#invoke:table|tableRange|(table)|3|7}} produces a table using rows 3-7 of the original table.
 
local wikitable = frame.args[1]
 
local wikitable = frame.args[1]
 
local rowP = rowPositions(wikitable)
 
local rowP = rowPositions(wikitable)
Line 99: Line 76:
 
end
 
end
   
function p.conditionalPartialTable(frame)
+
function p.tableRangeByString(frame)
  +
-- Like tableRange, but searches for two strings to determine the range.
-- Like p.partialTable but with row ranges specified using table contents. Usage: {{#invoke:table|conditionalPartialTable|(table)|first=|last=|col=(column number (optional))}}
 
-- For example, {{#invoke:table|conditionalPartialTable|(table)|1970|1980|col=1}} finds the first row where column 1 contains 1970 and the first row where column 1 contains 1980, and produces a table using all the rows in between except the row containing 1980.
+
-- {{#invoke:table|tableRangeByString|(table)|1970|1980}} produces a table starting from the first row that contains 1970 to the first row that contains 1980.
 
local wikitable = frame.args[1]
 
local wikitable = frame.args[1]
 
local rowP = rowPositions(wikitable)
 
local rowP = rowPositions(wikitable)
 
local length = rows(wikitable)
 
local length = rows(wikitable)
local firstRow = findFirstRow(wikitable, frame.args["first"], frame.args["col"]) or findFirstRow(wikitable, frame.args["first"]) or 1
+
local firstRow = findFirstRow(wikitable, frame.args[2]) or 1
local lastRow = findFirstRow(wikitable, frame.args["last"], frame.args["col"]) or findFirstRow(wikitable, frame.args["last"]) or length
+
local lastRow = findFirstRow(wikitable, frame.args[3]) - 1 or length - 1
lastRow = lastRow - 1
 
 
local header = string.sub(wikitable, 1, rowP[1] - 1)
 
local header = string.sub(wikitable, 1, rowP[1] - 1)
 
local body = fetchRows(wikitable, firstRow, lastRow)
 
local body = fetchRows(wikitable, firstRow, lastRow)
 
return header .. body .. "}"
 
return header .. body .. "}"
 
end
  +
  +
function p.splitTable(frame)
  +
-- Splits a table along a specified row.
  +
-- Example: {{#invoke:table|splitTable|(table)|130|==Header==}}
  +
local wikitable = frame.args[1]
  +
local rowP = rowPositions(wikitable)
 
local length = rows(wikitable)
 
local header = string.sub(wikitable, 1, rowP[1] - 1)
  +
local prevMarker = 1
  +
local nextMarker = 1
  +
local result = ""
  +
for n = 1, math.floor(#frame.args / 2) do
  +
prevMarker = nextMarker
  +
nextMarker = math.max(frame.args[2 * n], 1)
  +
local tween = frame.args[2 * n + 1] or ""
  +
local body = fetchRows(wikitable, prevMarker, nextMarker)
  +
result = result .. header .. body .. "}" .. tween
 
end
  +
return result .. header .. fetchRows(wikitable, nextMarker, length) .. "}"
 
end
 
end
   

Revision as of 03:46, 11 July 2020

Module for searching and manipulating wikitables.


-- Module for searching and manipulating wikitables.

local p = {}

local function delimiterPositions(wikitable, delimiter, ender)
    -- Gets the positions and number of instances of a delimiter in a table's wikitext. By "position", we mean that, for example, the letter "e" in "hello" is in position 2, and the pattern "ll" in "hello" is in position 3.
    local positions = {}
    local index = 1

    for pos = 1, string.len(wikitable) - 1 do
        if string.sub(wikitable, pos, pos + string.len(delimiter) - 1) == delimiter then
            positions[index] = pos
            index = index + 1
        elseif string.sub(wikitable, pos, pos + string.len(ender) - 1) == ender then
            positions[index] = pos
            break
        end
    end

    return {positions, index - 1}
end

local function rowPositions(wikitable)
    -- Gets the positions of instances of the row delimiter |- in a table's wikitext.
    return delimiterPositions(wikitable, "|-", "|}")[1]
end

local function rows(wikitable)
    -- Gets the number of rows in a table's wikitext.
    return delimiterPositions(wikitable, "|-", "|}")[2]
end

local function fetchRows(wikitable, firstRow, lastRow)
    -- Gets the contents of the rows between firstRow and lastRow inclusively. For example, fetchRows(wikitable, 3, 7) returns rows 3, 4, 5, 6, and 7 of the table.
    local rowP = rowPositions(wikitable)
    return string.sub(wikitable, rowP[firstRow], rowP[lastRow + 1])
end

local function fetchOneRow(wikitable, row)
    -- Gets the contents of a single row.
    return fetchRows(wikitable, row, row)
end

local function findFirstRow(wikitable, str)
    -- Finds the first row in the wikitable containing the requested string str.
    local rowP = rowPositions(wikitable)
    local pos, _ = string.find(wikitable, str)
    local i = 1
    while rowP[i] < pos do
        i = i + 1
    end
    return i - 1
end

local function columns(wikitable)
    -- Gets the names of the columns.
    local names = {}
    local posTable = delimiterPositions(wikitable, "!", "|-")
    for n = 1, posTable[2] do
        names[n] = string.sub(wikitable, posTable[1][n] + 1, posTable[1][n + 1] - 1)
    end
    return names
end

function p.tableRange(frame)
    -- Constructs a subtable of the given table containing the specified range of rows.
    -- {{#invoke:table|tableRange|(table)|3|7}} produces a table using rows 3-7 of the original table.
    local wikitable = frame.args[1]
    local rowP = rowPositions(wikitable)
    local length = rows(wikitable)
    local firstRow = math.max(frame.args[2], 1) or 1
    local lastRow = math.min(frame.args[3], length) or length
    local header = string.sub(wikitable, 1, rowP[1] - 1)
    local body = fetchRows(wikitable, firstRow, lastRow)
    return header .. body .. "}"
end

function p.tableRangeByString(frame)
    -- Like tableRange, but searches for two strings to determine the range.
    -- {{#invoke:table|tableRangeByString|(table)|1970|1980}} produces a table starting from the first row that contains 1970 to the first row that contains 1980.
    local wikitable = frame.args[1]
    local rowP = rowPositions(wikitable)
    local length = rows(wikitable)
    local firstRow = findFirstRow(wikitable, frame.args[2]) or 1
    local lastRow = findFirstRow(wikitable, frame.args[3]) - 1 or length - 1
    local header = string.sub(wikitable, 1, rowP[1] - 1)
    local body = fetchRows(wikitable, firstRow, lastRow)
    return header .. body .. "}"
end

function p.splitTable(frame)
    -- Splits a table along a specified row.
    -- Example: {{#invoke:table|splitTable|(table)|130|==Header==}}
    local wikitable = frame.args[1]
    local rowP = rowPositions(wikitable)
    local length = rows(wikitable)
    local header = string.sub(wikitable, 1, rowP[1] - 1)
    local prevMarker = 1
    local nextMarker = 1
    local result = ""
    for n = 1, math.floor(#frame.args / 2) do
        prevMarker = nextMarker
        nextMarker = math.max(frame.args[2 * n], 1)
        local tween = frame.args[2 * n + 1] or ""
        local body = fetchRows(wikitable, prevMarker, nextMarker)
        result = result .. header .. body .. "}" .. tween
    end
    return result .. header .. fetchRows(wikitable, nextMarker, length) .. "}"
end

return p

--[[Category:Modules]]