Lua-如果有2个特殊字符,请使用string.find返回true

时间:2019-02-08 06:00:37

标签: design-patterns lua lua-patterns

我需要一个可用于string.find(或必要时使用string.match)的模式,如果“表路径”字符串匹配,该模式将返回true。这是我的功能:

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")); -- prints "blue";

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

"module.<ANY>.color",其中<ANY>是“模块”的任何子表,并且还有一个名为“颜色”的子表,因此在向下遍历该表时,无论返回哪个表,都会返回一个值已使用(不必是外观表):

-- should also print "blue" ("setting." should not be required);
print(FindValueFromPattern(tbl, "module.<ANY>.color"));

我可能不必更改立即返回发现值的方法,而是必须更改逻辑以在表中插入发现值,然后在for循环之后返回表,但我很快编写了此代码来说明问题。

问题是,这种模式是什么样的?谢谢。

2 个答案:

答案 0 :(得分:0)

您在这里所做的工作效率极低。更好的方法是在每个.处拆分字符串,然后仅索引表。

一个不接受“ 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

这应该做您想要的。只需将“ *”更改为您想要的占位符即可。

答案 1 :(得分:0)

我使用gmatch和模式%.*([^.]+)来遍历提供的键中的每个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,并且直到代码运行时才知道是什么。