0

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

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Sewbacca
  • 576
  • 6
  • 17
  • 1
    `makeCaseInsensitive(pattern)` return 2 values: `[rR][eE][tT][aA][iI][nN][eE][dD]` and `8` ( result of `gsub`), therefore, it is incorrect to directly substitute the result into the construction `if`, this is a common mistake, you just need to know where it can meet – Mike V. Jul 30 '22 at 16:18
  • @MikeV. Oh, you are completly right, I forgot about the second return value and the extra argument to match. `function string.match(s: string, pattern: string, init?: integer)` has a third argument, taking the position to start. – Sewbacca Jul 30 '22 at 16:23
  • @MikeV. if you wish to have an accepted answer, post it and I will mark it. – Sewbacca Jul 30 '22 at 16:32

1 Answers1

1

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
Sewbacca
  • 576
  • 6
  • 17