模块:Quote:修订间差异
来自星露谷物语扩展百科
更多操作
无编辑摘要 |
无编辑摘要 |
||
| 第12行: | 第12行: | ||
-- 预编译的HTML模板片段(避免重复字符串拼接) | -- 预编译的HTML模板片段(避免重复字符串拼接) | ||
local HTML_TABLE_START = '<table class="quotetable"><tr><td rowspan="2" class="decorativesquote"></td><td class="' | local HTML_TABLE_START = '<table class="quotetable"><tr><td rowspan="2" class="decorativesquote"></td><td class="' | ||
local HTML_QUOTE_START = ' | local HTML_QUOTE_START = '“' | ||
local HTML_QUOTE_END = ' | local HTML_QUOTE_END = '”</td></tr>' | ||
local HTML_SOURCE_START = '<tr><td class="' | local HTML_SOURCE_START = '<tr><td class="' | ||
local HTML_SOURCE_MID = '">— ' | local HTML_SOURCE_MID = '">— ' | ||
| 第30行: | 第30行: | ||
local SOURCE_CLASS_ENGLISH = "quotesourceenglish" | local SOURCE_CLASS_ENGLISH = "quotesourceenglish" | ||
-- | -- UTF-8 字节序列常量(避免使用 mw.ustring) | ||
local COLON_UTF8 = "\239\188\154" -- ":" 的 UTF-8 字节序列 | |||
local COMMA_UTF8 = "\239\188\140" -- "," 的 UTF-8 字节序列 | |||
local PERIOD_UTF8 = "\227\128\130" -- "。" 的 UTF-8 字节序列 | |||
-- 内部函数:查找 UTF-8 字符的字节位置 | |||
local function findUtf8Char(text, pattern, startPos) | |||
startPos = startPos or 1 | |||
return text:find(pattern, startPos, true) -- 纯文本搜索,不使用模式匹配 | |||
end | |||
-- 内部函数:UTF-8 安全的字符串截取(完全避免 mw.ustring) | |||
local function utf8Sub(text, startPos, endPos) | |||
-- 对于我们的使用场景,直接使用字节位置即可 | |||
-- 因为我们已经通过 UTF-8 字节搜索确定了正确的位置 | |||
return text:sub(startPos, endPos) | |||
end | |||
-- 内部函数:分割引文文本(极致优化版本 - 最小化 mw.ustring 使用) | |||
local function splitQuote(text) | local function splitQuote(text) | ||
-- 快速检查:如果文本为空,返回空结果 | -- 快速检查:如果文本为空,返回空结果 | ||
| 第36行: | 第54行: | ||
return "", "" | return "", "" | ||
end | end | ||
local textLen = #text | local textLen = #text | ||
if textLen == 0 then | if textLen == 0 then | ||
| 第42行: | 第60行: | ||
end | end | ||
-- | -- 极致优化:使用字节级搜索查找冒号 | ||
local colonPos = | local colonPos = findUtf8Char(text, COLON_UTF8) | ||
if not colonPos then | |||
return "", text -- 没有冒号 | |||
-- | end | ||
-- 检查是否有第二个冒号 | |||
local secondColonPos = findUtf8Char(text, COLON_UTF8, colonPos + 3) -- +3 跳过第一个冒号的UTF-8字节 | |||
if secondColonPos then | |||
return "", text -- 有多个冒号 | |||
end | end | ||
- | -- 检查冒号前是否有中文标点 | ||
if | local beforeColonBytes = text:sub(1, colonPos - 1) | ||
if findUtf8Char(beforeColonBytes, COMMA_UTF8) or findUtf8Char(beforeColonBytes, PERIOD_UTF8) then | |||
return "", text | return "", text | ||
end | end | ||
-- | -- 分割文本(使用字节位置) | ||
local beforeColon = text:sub(1, colonPos - 1) | |||
local afterColon = text:sub(colonPos + 3) -- +3 跳过冒号的UTF-8字节 | |||
-- 处理特殊情况:'''和*开头 | |||
if textLen > colonPos + 2 then | |||
local firstByte = text:byte(colonPos + 3) | |||
local afterColon = | |||
-- | |||
if textLen > colonPos then | |||
local firstByte = text:byte(colonPos + | |||
-- ASCII 单引号 (39) 或星号 (42) 的快速检查 | -- ASCII 单引号 (39) 或星号 (42) 的快速检查 | ||
if firstByte == 39 then -- ' | if firstByte == 39 then -- ' | ||
if afterColon:sub(1, 3) == TRIPLE_QUOTE then | |||
if | afterColon = afterColon:sub(4) | ||
beforeColon = beforeColon .. TRIPLE_QUOTE | |||
end | end | ||
elseif firstByte == 42 then -- * | elseif firstByte == 42 then -- * | ||
if afterColon:sub(1, 1) == "*" then | |||
if | afterColon = STAR_SPAN .. afterColon:sub(2) | ||
afterColon = STAR_SPAN .. | |||
end | end | ||
end | end | ||
end | end | ||
2025年7月10日 (四) 18:59的版本
local p = {}
-- 缓存全局变量以减少重复调用
local quoteLast = ""
-- 预编译的正则表达式模式(避免重复编译)
local COLON_PATTERN = ":"
local PUNCT_PATTERN = "[,。]"
local TRIPLE_QUOTE = "'''"
local STAR_SPAN = "<span>*</span>"
-- 预编译的HTML模板片段(避免重复字符串拼接)
local HTML_TABLE_START = '<table class="quotetable"><tr><td rowspan="2" class="decorativesquote"></td><td class="'
local HTML_QUOTE_START = '“'
local HTML_QUOTE_END = '”</td></tr>'
local HTML_SOURCE_START = '<tr><td class="'
local HTML_SOURCE_MID = '">— '
local HTML_SOURCE_END = '</td></tr>'
local HTML_TABLE_END = '</table>'
local COLON_CHAR = ':'
-- 性别标记检查的预编译模式
local MALE_MARKER = "(男)"
local FEMALE_MARKER = "(女)"
-- 样式类名预编译
local TEXT_CLASS_NORMAL = "squotetext"
local TEXT_CLASS_ENGLISH = "squotetextenglish"
local SOURCE_CLASS_NORMAL = "quotesource"
local SOURCE_CLASS_ENGLISH = "quotesourceenglish"
-- UTF-8 字节序列常量(避免使用 mw.ustring)
local COLON_UTF8 = "\239\188\154" -- ":" 的 UTF-8 字节序列
local COMMA_UTF8 = "\239\188\140" -- "," 的 UTF-8 字节序列
local PERIOD_UTF8 = "\227\128\130" -- "。" 的 UTF-8 字节序列
-- 内部函数:查找 UTF-8 字符的字节位置
local function findUtf8Char(text, pattern, startPos)
startPos = startPos or 1
return text:find(pattern, startPos, true) -- 纯文本搜索,不使用模式匹配
end
-- 内部函数:UTF-8 安全的字符串截取(完全避免 mw.ustring)
local function utf8Sub(text, startPos, endPos)
-- 对于我们的使用场景,直接使用字节位置即可
-- 因为我们已经通过 UTF-8 字节搜索确定了正确的位置
return text:sub(startPos, endPos)
end
-- 内部函数:分割引文文本(极致优化版本 - 最小化 mw.ustring 使用)
local function splitQuote(text)
-- 快速检查:如果文本为空,返回空结果
if not text then
return "", ""
end
local textLen = #text
if textLen == 0 then
return "", ""
end
-- 极致优化:使用字节级搜索查找冒号
local colonPos = findUtf8Char(text, COLON_UTF8)
if not colonPos then
return "", text -- 没有冒号
end
-- 检查是否有第二个冒号
local secondColonPos = findUtf8Char(text, COLON_UTF8, colonPos + 3) -- +3 跳过第一个冒号的UTF-8字节
if secondColonPos then
return "", text -- 有多个冒号
end
-- 检查冒号前是否有中文标点
local beforeColonBytes = text:sub(1, colonPos - 1)
if findUtf8Char(beforeColonBytes, COMMA_UTF8) or findUtf8Char(beforeColonBytes, PERIOD_UTF8) then
return "", text
end
-- 分割文本(使用字节位置)
local beforeColon = text:sub(1, colonPos - 1)
local afterColon = text:sub(colonPos + 3) -- +3 跳过冒号的UTF-8字节
-- 处理特殊情况:'''和*开头
if textLen > colonPos + 2 then
local firstByte = text:byte(colonPos + 3)
-- ASCII 单引号 (39) 或星号 (42) 的快速检查
if firstByte == 39 then -- '
if afterColon:sub(1, 3) == TRIPLE_QUOTE then
afterColon = afterColon:sub(4)
beforeColon = beforeColon .. TRIPLE_QUOTE
end
elseif firstByte == 42 then -- *
if afterColon:sub(1, 1) == "*" then
afterColon = STAR_SPAN .. afterColon:sub(2)
end
end
end
return beforeColon, afterColon
end
-- 主要的 squote 函数,处理整个引文模板逻辑(极致优化版本)
function p.squote(frame)
local args = frame.args
local text = args[1] or "引文"
local source = args[2] or ""
local textStyle = args.text or ""
-- 分割引文
local quoteBefore, quoteAfter = splitQuote(text)
-- 极致优化:预计算所有条件
local hasQuoteBefore = quoteBefore ~= ""
local shouldClearBefore = false
if hasQuoteBefore and quoteBefore == quoteLast then
-- 性别标记检查:使用预编译的常量和字节级搜索
local afterText = quoteAfter
local hasGenderMarker = afterText:find(MALE_MARKER, 1, true) or afterText:find(FEMALE_MARKER, 1, true)
shouldClearBefore = not hasGenderMarker
end
-- 预计算样式类名
local isEnglish = textStyle == "english"
local textClass = isEnglish and TEXT_CLASS_ENGLISH or TEXT_CLASS_NORMAL
-- 构建HTML结果(极致优化:使用table.concat减少字符串拼接开销)
local htmlParts = {}
local partCount = 0
-- 添加表格开始和文本类
partCount = partCount + 1
htmlParts[partCount] = HTML_TABLE_START .. textClass .. '">'
-- 添加说话人(如果需要)
if hasQuoteBefore and not shouldClearBefore then
partCount = partCount + 1
htmlParts[partCount] = quoteBefore .. COLON_CHAR
-- 更新缓存的说话人
quoteLast = quoteBefore
-- 延迟设置全局变量到最后(减少中断)
frame:callParserFunction('#vardefine', {'quote_last', quoteBefore})
end
-- 添加引文内容
partCount = partCount + 1
htmlParts[partCount] = HTML_QUOTE_START
partCount = partCount + 1
if quoteAfter ~= "" then
htmlParts[partCount] = quoteAfter
else
htmlParts[partCount] = text -- 如果没有成功分割,使用原文本
end
partCount = partCount + 1
htmlParts[partCount] = HTML_QUOTE_END
-- 添加来源行(如果提供了来源)
if source ~= "" then
local sourceClass = isEnglish and SOURCE_CLASS_ENGLISH or SOURCE_CLASS_NORMAL
partCount = partCount + 1
htmlParts[partCount] = HTML_SOURCE_START .. sourceClass .. HTML_SOURCE_MID .. source .. HTML_SOURCE_END
end
partCount = partCount + 1
htmlParts[partCount] = HTML_TABLE_END
-- 一次性拼接所有HTML片段(最高效的字符串拼接方法)
return table.concat(htmlParts, "", 1, partCount)
end
return p