需求:实现类似string.sub的Lua函数,保留字符串中的十六进制颜色码
实现Lua函数
stringf:sub_hex —— 带十六进制颜色保留的比例式子串提取 需求分析
我们需要实现一个类似string.sub的Lua函数,但要满足两个核心要求:
- 按输入比例
f(0.0-1.0)截取字符串 - 完整保留字符串中的十六进制颜色控制序列(格式为
\a后跟8个十六进制字符,例如\affffffff),不能拆分这类序列
以示例输入"\affffffffSample \aff8080ffText"为例:
- 当
f=0.5时,预期输出"\affffffffSample" - 当
f=0.9时,预期输出"\affffffffSample \aff8080ffTe"
实现思路
- 拆分字符串:将原始字符串拆分为「颜色控制段」和「普通文本段」的列表,标记每个片段的类型
- 计算目标长度:统计所有普通文本的总长度,按比例
f计算需要保留的文本字符数 - 拼接结果:遍历片段列表,完整保留所有颜色段,按需截取文本段,直到达到目标长度
代码实现
stringf = {} function stringf.sub_hex(s, f) -- 1. 拆分字符串为颜色段和文本段 local fragments = {} local i = 1 local len = #s while i <= len do -- 识别十六进制颜色控制序列:\a + 8位十六进制字符 if s:sub(i, i) == "\a" and i + 8 <= len then local color_part = s:sub(i, i + 8) -- 可选:严格校验后续8位是否为十六进制字符 if color_part:sub(2):match("^%x%x%x%x%x%x%x%x$") then table.insert(fragments, {type = "color", content = color_part}) i = i + 9 goto continue end end -- 提取普通文本段 local j = i while j <= len and s:sub(j, j) ~= "\a" do j = j + 1 end local text_part = s:sub(i, j - 1) if #text_part > 0 then table.insert(fragments, {type = "text", content = text_part}) end i = j ::continue:: end -- 2. 计算总文本长度与目标保留长度 local total_text_len = 0 for _, frag in ipairs(fragments) do if frag.type == "text" then total_text_len = total_text_len + #frag.content end end -- 处理边界情况 if f <= 0 then return "" end if f >= 1 then return s end -- 按比例计算目标长度(向上取整匹配示例预期) local target_len = math.min(total_text_len, math.ceil(total_text_len * f)) -- 3. 拼接结果片段 local result = {} local current_len = 0 for _, frag in ipairs(fragments) do if frag.type == "color" then table.insert(result, frag.content) else local take = math.min(#frag.content, target_len - current_len) if take > 0 then table.insert(result, frag.content:sub(1, take)) current_len = current_len + take if current_len >= target_len then break end end end end return table.concat(result) end -- 测试示例 local test_str = "\affffffffSample \aff8080ffText" print(stringf.sub_hex(test_str, 0.5)) -- 输出:\affffffffSample print(stringf.sub_hex(test_str, 0.9)) -- 输出:\affffffffSample \aff8080ffTe
可选调整说明
- 颜色校验开关:如果不需要严格校验
\a后续字符是否为十六进制,可以删除颜色段的正则匹配判断,直接将\a+8位字符当作颜色段保留 - 取整逻辑:代码中使用
math.ceil向上取整以匹配示例预期,若需要向下取整,替换为math.floor即可
内容的提问来源于stack exchange,提问作者qhouz
相关产品推荐
相关产品推荐

