문서 편집 권한이 없습니다. 다음 이유를 확인해주세요: 요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다: 사용자. 문서의 원본을 보거나 복사할 수 있습니다. local p = {} local u = mw.ustring -- hot locals local str_gsub, str_find, str_match, tbl_concat = string.gsub, string.find, string.match, table.concat -- CSV -> array (simple; same behavior as your original) local function csv_to_array(csv) local rows = {} for line in tostring(csv):gmatch("[^\r\n]+") do local row = {} for cell in line:gmatch("([^,]+)") do cell = cell:gsub("^%s+", ""):gsub("%s+$", "") row[#row+1] = cell end rows[#rows+1] = row end return rows end -- transpose without re-stringifying local function transpose(m, fill) fill = fill or "" local out, rows, maxc = {}, #m, 0 for r = 1, rows do if #m[r] > maxc then maxc = #m[r] end end for c = 1, maxc do local newrow = {} for r = 1, rows do newrow[r] = m[r][c] or fill end out[c] = newrow end return out end -- per-char wrapper for text contained in single quotes, with memoization local justify_cache = setmetatable({}, { __mode = "kv" }) local function justifys(s) return u.gsub(s, "'(.-)'", function(inner) local cached = justify_cache[inner] if cached then return cached end local pieces = {} for ch in u.gmatch(inner, ".") do pieces[#pieces+1] = "<span>" .. ch .. "</span>" end local out = '<span class="justify-chars">' .. tbl_concat(pieces) .. "</span>" justify_cache[inner] = out return out end) end -- Memoizers for C{...} and S{...} local C_cache = setmetatable({}, { __mode = "kv" }) local S_cache = setmetatable({}, { __mode = "kv" }) local N_cache = setmetatable({}, { __mode = "kv" }) -- Memoizers for BC{...} and BS{...} local BC_cache = setmetatable({}, { __mode = "kv" }) local BS_cache = setmetatable({}, { __mode = "kv" }) local function transform_BC(inner) local cached = BC_cache[inner]; if cached then return cached end inner = inner:gsub("^%s*(.-)%s*$", "%1") local out if tonumber(inner) ~= nil then out = '<span class="forcedcenter" style="font-family: SeoulAlrimTTF, Zen Kaku Gothic Antique, CUSTOMFONT, TIMETABLEFONT, TIMETABLEFONT2 !important; height: 1rem; width: 1.9rem; display: inline-block; border: 1px solid var(--text); border-radius: 40%; font-size: 0.75rem; line-height: 1; position: relative; vertical-align: middle; overflow: hidden; background: var(--text); color: var(--bg);">' .. inner .. '</span>' else out = '<span class="forcedcenter" style="height: 1rem; width: 1.9rem; display: inline-block; border: 1px solid var(--text); border-radius: 40%; font-size: 0.75rem; line-height: 1.1; position: relative; vertical-align: middle; overflow: hidden; background: var(--text); color: var(--bg);"><span class="stretch-text" data-max-width="1.22rem"><span>' .. inner .. '</span></span></span>' end BC_cache[inner] = out return out end local function transform_N(inner) local cached = N_cache[inner]; if cached then return cached end inner = inner:gsub("^%s*(.-)%s*$", "%1") out = '<span class="seriftt">' .. inner .. '</span>' N_cache[inner] = out return out end local function transform_BS(inner) local cached = BS_cache[inner]; if cached then return cached end inner = inner:gsub("^%s*(.-)%s*$", "%1") local out if tonumber(inner) ~= nil then out = '<span class="forcetopalign forcedcenter" style="height: 0.95rem; width: 1.8rem; display: inline-block; overflow: hidden; border: 1px solid var(--text); font-size: 0.75rem; line-height: 0.9; vertical-align: middle; background: var(--text); color: var(--bg);">' .. inner .. '</span>' else out = '<span class="forcetopalign forcedcenter" style="height: 1rem; width: 1.9rem; display: inline-block; overflow: hidden; border: 1px solid var(--text); font-size: 0.75rem; position: relative; line-height: 1.1; vertical-align: middle; background: var(--text); color: var(--bg);"><span class="stretch-text" data-max-width="1.4rem"><span>' .. inner .. '</span></span></span>' end BS_cache[inner] = out return out end local function transform_C(inner) local cached = C_cache[inner]; if cached then return cached end inner = inner:gsub("^%s*(.-)%s*$", "%1") local as_num = tonumber(inner) local result if as_num and as_num >= 0 and as_num <= 34 then if as_num == 0 then result = "⓪" elseif as_num <= 20 then result = '<span class="forcedcenter"></span>' .. u.char(0x2460 + (as_num - 1)) else result = '<span class="forcedcenter"></span>' .. u.char(0x3251 + (as_num - 21)) end elseif as_num then result = '<span class="forcedcenter" style="font-family: SeoulAlrimTTF, Zen Kaku Gothic Antique, CUSTOMFONT, TIMETABLEFONT, TIMETABLEFONT2 !important; height: 1rem; width: 1.9rem; display: inline-block; border: 1px solid var(--text); border-radius: 40%; font-size: 0.75rem; line-height: 1; position: relative; vertical-align: middle; overflow: hidden;">' .. inner .. '</span>' else result = '<span class="forcedcenter" style="height: 1rem; width: 1.9rem; display: inline-block; border: 1px solid var(--text); border-radius: 40%; font-size: 0.75rem; line-height: 1.1; position: relative; vertical-align: middle; overflow: hidden;"><span class="stretch-text" data-max-width="1.22rem"><span>' .. inner .. '</span></span></span>' end C_cache[inner] = result return result end local function transform_S(inner) local cached = S_cache[inner]; if cached then return cached end inner = inner:gsub("^%s*(.-)%s*$", "%1") local result if tonumber(inner) ~= nil then result = '<span class="forcetopalign forcedcenter" style="height: 0.95rem; width: 1.8rem; display: inline-block; overflow: hidden; border: 1px solid var(--text); font-size: 0.75rem; line-height: 0.9; vertical-align: middle;">' .. inner .. '</span>' else result = '<span class="forcetopalign forcedcenter" style="height: 1rem; width: 1.9rem; display: inline-block; overflow: hidden; border: 1px solid var(--text); font-size: 0.75rem; position: relative; line-height: 1.1; vertical-align: middle;"><span class="stretch-text" data-max-width="1.4rem"><span>' .. inner .. '</span></span></span>' end S_cache[inner] = result return result end -- Single-pass token normalizer for most ASCII tokens (multi-char handled first) local function normalize_tokens(value) -- multi-char first value = str_gsub(value, "%-%-", "DOUBLEFINISHLINE") value = str_gsub(value, ">>", "➡") value = str_gsub(value, "%.%.", "FULLSTOP") -- single-char bucket via callback value = str_gsub(value, "([<>h~r#&g%^;x.iq%-/vkb])", function(ch) if ch == "<" then return " colspan=" elseif ch == ">" then return "⇨" elseif ch == ">" then return "⇨" elseif ch == "h" then return "HEADERSTYLE" elseif ch == "~" then return "HEIGHTSET" elseif ch == "r" then return "RIGHTLEFT" elseif ch == "n" then return "OPENTCUSPAN" elseif ch == "#" then return "NOBORDERTOP" elseif ch == "&" then return "YESBORDERTOP" elseif ch == "g" then return "GREATER" elseif ch == "^" then return " rowspan=" elseif ch == ";" then return " |" elseif ch == "x" then return "ELLIPSIS" elseif ch == "." then return "ENDSPAN" elseif ch == "i" then return "OPENCENTERSPAN|" elseif ch == "q" then return "OPENCENTERSPAN〃" elseif ch == "-" then return "OPENCENTERSPAN_" elseif ch == "v" then return "OPENCENTERSPAN↓" elseif ch == "k" then return '<span style="font-weight: 700;">' elseif ch == "b" then return '<span style="font-size: 1.25em; font-weight: 700;">' elseif ch == "/" then return "<br/>" end return ch end) -- post-placeholders (same order as your original) value = str_gsub(value, "ENDSPAN","</span>") value = str_gsub(value, "ELLIPSIS",'OPENCENTERSPAN⋯') value = str_gsub(value, "OPENSPAN", '<span></span>') value = str_gsub(value, "HEADERSTYLE", [[colspan="]] .. "3" .. [[" style="padding-left: 1.08rem; padding-right: 1.08rem; text-align: justify; text-align-last: justify; border-right: none; vertical-align: middle;"]]) value = str_gsub(value, "HEIGHTSET", ' height=') value = str_gsub(value, "RIGHTLEFT", '<span class="wm-rl">') value = str_gsub(value, "NOBORDERTOP", '<span class="nobordertop"></span>') value = str_gsub(value, "YESBORDERTOP", '<span class="yesbordertop"></span>') value = str_gsub(value, "GREATER", '<span style="font-size: 1.2em;">') value = str_gsub(value, "OPENCENTERSPAN", '<span class="forcedcenter"></span>') value = str_gsub(value, "DOUBLEFINISHLINE", '<span class="forcedcenter">=</span>') value = str_gsub(value, "FULLSTOP", '%.') value = str_gsub(value, "OPENTCUSPAN", '<span style="text-combine-upright: all;">') return value end -- Per-cell full transform (order preserved vs your original) local function transform_cell(raw) if str_find(raw, "!!", 1, true) then return "!!" -- keep placeholder; no transforms end local v = raw -- simple markers first v = str_gsub(v, "c", 'OPENCENTERSPAN') -- left as-is from your order -- normalize tokens & placeholders v = normalize_tokens(v) -- fixed symbols / arrows (same as your code) v = str_gsub(v, "DEP", '<span style="font-size: 0.92rem;">發</span>') v = str_gsub(v, "ARR", '<span style="font-size: 0.92rem;">着</span>') v = str_gsub(v, "DIV", '<span class="forcedcenter" style="font-size: 1.1rem; vertical-align: middle; line-height: 0.9rem;">╌</span>') v = str_gsub(v, "GRR", '<span class="forcedcenter"></span>') v = str_gsub(v, "GRN", '<span class="forcedcenter"></span>') v = str_gsub(v, "LEX", '<span class="forcedcenter" style="font-size: 1.8rem; display: inline-block; margin-top: 7px;"></span>') v = str_gsub(v, "LSL", '<span class="forcetopalign forcedcenter" style="font-size: 1.8rem; display: inline-block; margin-top: 7px;">🌃</span>') v = str_gsub(v, "XSL", '<span class="forcetopalign forcedcenter" style="font-size: 1.8rem; display: inline-block; margin-top: 7px;"></span>') v = str_gsub(v, "TRD", '<span class="forcedcenter">⬎</span>') v = str_gsub(v, "TRU", '<span class="forcedcenter">⬏</span>') v = str_gsub(v, "TLD", '<span class="forcedcenter">⬐</span>') v = str_gsub(v, "TLU", '<span class="forcedcenter">⬑</span>') v = str_gsub(v, "TDL", '<span class="forcedcenter">↲</span>') v = str_gsub(v, "TDR", '<span class="forcedcenter">↳</span>') v = str_gsub(v, "TUL", '<span class="forcedcenter">↰</span>') v = str_gsub(v, "TUR", '<span class="forcedcenter">↱</span>') v = str_gsub(v, "MLD", '<span class="forcedcenter">┏</span>') v = str_gsub(v, "MRD", '<span class="forcedcenter">┓</span>') v = str_gsub(v, "MLU", '<span class="forcedcenter">┗</span>') v = str_gsub(v, "MRU", '<span class="forcedcenter">┛</span>') v = str_gsub(v, "TNO", '<span class="forcedcenter" style="display: block; margin-top: -7.5px; height: 0;">[</span>') v = str_gsub(v, "TNC", '<span class="forcedcenter" style="display: block; margin-top: -3px; height: 0; margin-bottom: -6px;">]</span>') v = str_gsub(v, "SUO", '<span class="forcedcenter" style="display: block; margin-top: -7.5px; height: 0;">{</span>') v = str_gsub(v, "SUC", '<span class="forcedcenter" style="display: block; margin-top: -3px; height: 0; margin-bottom: -6px;">}</span>') v = str_gsub(v, "PAO", '<span class="forcedcenter" style="display: block; margin-top: -7.5px; height: 0;">(</span>') v = str_gsub(v, "PAC", '<span class="forcedcenter" style="display: block; margin-top: -3px; height: 0; margin-bottom: -6px;">)</span>') v = str_gsub(v, "SPA", '<span class="forcedcenter"> </span>') -- C{...} and S{...} v = u.gsub(v, 'BC{(.-)}', transform_BC) v = u.gsub(v, 'BS{(.-)}', transform_BS) v = u.gsub(v, 'C{(.-)}', transform_C) v = u.gsub(v, 'S{(.-)}', transform_S) v = u.gsub(v, 'N{(.-)}', transform_N) -- quoted per-char justify v = justifys(v) return v end function p.csv(frame) local headerRowCount = tonumber(frame.args["header"]) or 4 local headerColCount = tonumber(frame.args["left"]) or 3 local footerRowCount = tonumber(frame.args["footer"]) or 1 local title = frame.args["title"] or '제목 (title 변수 입력)' local csv = frame.args[1] or '' -- title transforms (unchanged) title = title:gsub(">", '—') title = title:gsub("%.", '</div>') title = title:gsub("u", 'UNBOLD') title = title:gsub("k", 'KUDARI') title = title:gsub("n", 'NOBORI') title = title:gsub("l", '<div style="border: var(--text) 1.5px solid; display: inline-block; padding-top: 2px; padding-bottom: 3px; font-size: 1.14rem; font-weight: normal; vertical-align: top; line-height: 1.35rem;">') title = title:gsub("UNBOLD", '<div style="font-weight: 400; display: inline; font-size: 1.17rem; vertical-align: 1.5px; vertical-align: -webkit-baseline-middle;">') title = title:gsub("KUDARI", '<div class="arrow arrow--down outline">') title = title:gsub("NOBORI", '<div class="arrow arrow--up solid">') -- parse once, transpose once local arr = csv_to_array(csv) arr = transpose(arr) local out = {} out[#out+1] = '<div style="display: flex; flex-direction: row; padding-bottom: 1rem;"><div class="wm-rl timetabletitle" style="font-size: 1.26rem; padding-right: 4px; font-weight: 700; line-height: 1.54rem;">' out[#out+1] = title out[#out+1] = '</div><div style="border: 2.5px solid var(--text); padding: 3px !important; overflow-x: scroll;">\n{| class="timetable" style="text-align: right; border-spacing: 30px;"\n' local total_rows = #arr for i = 1, total_rows do local row = arr[i] local values = {} for c = 1, #row do local v = transform_cell(row[c]) if not str_find(v, "|", 1, true) then v = "|" .. v end if v then values[#values+1] = v end end -- prepend style per column index (same logic/order as yours) for j = 1, #values do if j == headerColCount - 2 then values[j] = [[style="vertical-align: middle !important; text-align: justify; text-align-last: justify; border-right: none;"]] .. values[j] elseif j == headerColCount - 1 then values[j] = [[style="padding-left: 0.2rem; padding-right: 0.2rem; text-align: justify; text-align-last: justify; border-right: none; vertical-align: middle !important; min-width: 8.5ch;"]] .. values[j] elseif j == headerColCount then values[j] = 'style="text-align: center; border-left: none; border-right: 1px solid var(--text); margin-left: -1rem;"' .. values[j] elseif j == headerColCount + 1 then values[j] = [[style="width: 37.5px; border-left: 1px solid var(--text);"]] .. values[j] elseif j < headerColCount - 2 then values[j] = [[style="border-right: 1px solid;"]] .. values[j] else values[j] = [[style="width: 37.5px; border-left: 1px solid var(--text);"]] .. values[j] end end for j = #values, 1, -1 do if string.find(values[j], "!!", 1, true) then table.remove(values, j) end end -- row separators (unchanged semantics) if i < headerRowCount + 1 then out[#out+1] = '|- style="border-top: 1px solid var(--text);"\n| ' out[#out+1] = tbl_concat(values, " \n| ") out[#out+1] = "\n" elseif i == headerRowCount + 1 then out[#out+1] = '|- style="border-top: double var(--text);"\n| ' out[#out+1] = tbl_concat(values, " \n| ") out[#out+1] = "\n" elseif i == total_rows - footerRowCount + 1 then out[#out+1] = '|- style="border-top: double var(--text);"\n| ' out[#out+1] = tbl_concat(values, " \n| ") out[#out+1] = "\n" elseif i > total_rows - footerRowCount + 1 then out[#out+1] = '|- style="border-top: 1px solid var(--text);"\n| ' out[#out+1] = tbl_concat(values, " \n| ") out[#out+1] = "\n" else out[#out+1] = "|-\n| " out[#out+1] = tbl_concat(values, " \n| ") out[#out+1] = "\n" end end out[#out+1] = "|}\n</div></div>" return tbl_concat(out) end return p 이 문서에서 사용한 틀: 모듈:Timetable/설명문서 (원본 보기) 모듈:Timetable 문서로 돌아갑니다.