Lua - 使用 string.find 来判断是否在两个特定字符之间

我需要一个能够与 string.find(或如果必要的话是 string.match)一起工作且能够匹配“表路径”字符串的模式。这是我的函数:

local function FindValueFromPattern(myTable, pattern, previousPath)
    for key, value in pairs(myTable) do
        local path;

        if (not previousPath) then
            path = key;
        else
            path = string.format("%s.%s", previousPath, key);
        end

        if (path:find(pattern)) then
            return value;

        elseif (type(value) == "table") then
            value = FindValueFromPattern(value, pattern, path);

            if (value ~= nil) then
               return value;
            end
        end
    end

    return nil;
end

local tbl = {}
tbl.settings = {};
tbl.settings.module = {};
tbl.settings.module.appearance = {};
tbl.settings.module.appearance.color = "blue";

print(FindValueFromPattern(tbl, "settings.module.appearance.color")); -- 输出 "blue";

上面的代码是有效的,但我现在想将模式更改为:

"module.<ANY>.color" 其中 <ANY> 是“module”下的任何子表,也有一个名为“color”的子表,因此在遍历表时,无论使用哪个表都会返回一个值(不必是 appearance 表):

-- 也应该输出 "blue"(不需要 "setting.");
print(FindValueFromPattern(tbl, "module.<ANY>.color"));

我可能不会立即返回找到的值,而是要更改逻辑以在 for 循环后将找到的值插入到表中,然后返回该表,但我很快写下了这个问题。

所以问题是,该模式会是什么样子呢?谢谢。

点赞
用户4984564
用户4984564

你现在在做的非常低效。一个更好的方法是在每个 . 上将字符串分割并索引表。

一个简单版本,不接受 "any" 可以像这样:

function findintable(tab, path)
    local pos = path:find(".", 1, true)
    if pos then
        local tab = tab[path:sub(1, pos-1)]
        if not type(tab) then error("Expected value to be table, got "..type(tab), 1) end
        return findintable(tab, path:sub(pos+1, -1))
    else
        return tab[path]
    end
end

如果要添加 任意键 (嘿嘿嘿...),它会增加一些复杂性并需要一个循环,但也是可行的。

function findintable(tab, path)
    local pos = path:find(".", 1, true)
    if not pos then
        return tab[path]
    end
    local key, rest = path:sub(1, pos-1), path:sub(pos+1, -1)
    if key == "*" then
        for k, v in pairs(tab) do
            if type(v)~="table" then return end
            local res = findintable(v, rest)
            if res then return res end
        end
        return
    else
        local tab = tab[path:sub(1, pos-1)]
        if not type(tab) then error("Expected value to be table, got "..type(tab), 1) end
        return findintable(tab, path:sub(pos+1, -1))
    end
end

这样应该能够实现你想要的效果。只需将 "*" 更改为占位符即可。

2019-02-08 11:51:10
用户7396148
用户7396148

我使用 gmatch 和模式 %.*([^.]+) 对所提供的 keys 中的每个 key 进行迭代。

该函数可以更改为输出找到的所有 color 的表,但目前仅返回单个值。返回的值是找到的 color,如果没有找到匹配项,则返回 nil

function FindValueFromPattern(tab, keys)
    local t_ref = tab

    for k in keys:gmatch("%.*([^.]+)") do
        if k == "<ANY>" and type(t_ref) == "table" then
            local temp1
            local temp2

            for any in pairs(t_ref) do
                local new_keys = keys:gsub(k, any)
                temp1 = FindValueFromPattern(tab, new_keys)

                new_keys = keys:gsub(k, any .. ".<ANY>")
                temp2 = FindValueFromPattern(tab, new_keys)

                if temp1 or temp2 then
                    break
                end
            end
            t_ref = temp1 or temp2
            break
        else
            if t_ref == nil or type(t_ref) ~= "table" then
                t_ref = nil
                break
            end

            t_ref = t_ref[k]
        end
    end
    return t_ref
end

使用示例:

sample = {
    a = {
        b = {
            c = {
                color = "blue",

            },
            roloc = 1,
            color = "red",
        },
        d = {
            e = {
                color = "purple",

            },
            roloc = "wolley",
            color = "yellow",
        },
    }
}
colorFound = FindValueFromPattern(sample, "a.<ANY>.color")
if colorFound then
    print("Found: " .. colorFound )
else
    print("No matches found")
end
>> Found: red

请记住,其行为是不确定的,输出可能是 yellow 而不是 red,直到代码被运行才能知道它将是哪个输出。

2019-02-11 19:38:17