Search code examples
lualuajitlua-patterns

Weird matching behaviour and argument interpretation in Lua


Somehow there seems to be a difference, when passing a string in via a variable vs. passing a string via an expression as an argument.

I am so confused right now, about how Lua evaluates expressions. In short: I am trying to detect a word, case insensitive and I am reformatting the pattern, so it is not case sensitive. If I pass the argument directly to <string>:match (sidenote: issue persists with directly calling string.match), it doesn't give the expected behaviour, while it does, when passing it via a local variable.

I have destilled the code into a reproducable script (Windows: Lua 5.4.3 and Lua JIT 2.1.0-beta3, WSL: Lua 5.3.3, Linux: Lua 5.1):

-- Replaces each char with a charset pattern in uppercase and lowercase
local function makeCaseInsensitive(name)
    return name:gsub("%a", function (c)
        return string.format("[%s%s]", c:lower(), c:upper())
    end)
end

local suite = "Retained widgets"
local pattern = "retained"

if suite:match(makeCaseInsensitive(pattern)) then
    print("In expression ok")
else
    print("In expression not ok")
end

local insensitive = makeCaseInsensitive(pattern)
if suite:match(insensitive) then
    print("In variable ok")
else
    print("In variable not ok")
end

The expected output would be:

In expression ok
In variable ok

instead:

In expression not ok
In variable ok

WTF is going on? Could someone please explain to me, what is going on?

Any feedback is appreciated


Solution

  • As @MikeV. pointed out in the comments: makeCaseInsensitive(pattern) returns two arguments. This is due to string.gsub returning the replacement and the replaced character count: 8.

    The solution is to discard the rest from gsub, either explicitly:

    -- Replaces each char with a charset pattern in uppercase and lowercase
    local function makeCaseInsensitive(name)
        local caseInsensitivePattern, count = name:gsub("%a", function (c)
            return string.format("[%s%s]", c:lower(), c:upper())
        end)
        return caseInsensitivePattern
    end
    

    or implicitly by adding extra parenthesis:

    -- Replaces each char with a charset pattern in uppercase and lowercase
    local function makeCaseInsensitive(name)
        return (name:gsub("%a", function (c)
            return string.format("[%s%s]", c:lower(), c:upper())
        end))
    end