You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

需求:实现类似string.sub的Lua函数,保留字符串中的十六进制颜色码

实现Lua函数stringf:sub_hex —— 带十六进制颜色保留的比例式子串提取

需求分析

我们需要实现一个类似string.sub的Lua函数,但要满足两个核心要求:

  1. 按输入比例f(0.0-1.0)截取字符串
  2. 完整保留字符串中的十六进制颜色控制序列(格式为\a后跟8个十六进制字符,例如\affffffff),不能拆分这类序列

以示例输入"\affffffffSample \aff8080ffText"为例:

  • 当f=0.5时,预期输出"\affffffffSample"
  • 当f=0.9时,预期输出"\affffffffSample \aff8080ffTe"

实现思路

  1. 拆分字符串:将原始字符串拆分为「颜色控制段」和「普通文本段」的列表,标记每个片段的类型
  2. 计算目标长度:统计所有普通文本的总长度,按比例f计算需要保留的文本字符数
  3. 拼接结果:遍历片段列表,完整保留所有颜色段,按需截取文本段,直到达到目标长度

代码实现

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:45:34