Search code examples
lualua-patterns

way to set dynamic pattern matcher


Please look into this question Pattern ^u.meta(\.|$) not working as expected which has the expected behavior that I need.

CHANGES

In pattern ^u.meta(\.|$) or in lua '^u%.meta%f[\0.]' or '^u%.meta%f[%z.]', the change I need is u.meta can be anything that user defined from variable. And pattern should be generic/dynamic to match what is set in the variable.

For example:

-- should return 'u.meta', and pattern should match
local pattern = 'u.meta'
print(string.match("u.meta.admin", '^u%.meta%f[\0.]')) -- u.meta

-- should return 'nil', and pattern should fail
local pattern = 'u.meta'
print(string.match("u.domain.admin", '^u%.meta%f[\0.]')) -- nil

-- should return 'anything.anything', and pattern should match
local pattern = 'anything.anything'
print(string.match("anything.anything.something", '^anything%.anything%f[\0.]') -- anything.anything

-- should return nil, and pattern should fail
local pattern = 'anything.anything'
print(string.match("fake.fake.something", '^anything%.anything%f[\0.]') -- nil

SOLUTION 1

so, what I was thinking is something like interpolation in lua pattern, if possible.

"^#{pattern}%f[\0.]"

WORKING SOLUTION 2

I have made it working with the help of method. But still I have to call those pattern manually. If we can fix this from pattern itself, it would be great

Example:

function pattern_matcher(v, pattern) return string.match(v, pattern) end

print(pattern_matcher("fake.fake.something", '^u%.meta%f[%z.]')) -- nil
print(pattern_matcher("u.meta.something", '^u%.meta%f[%z.]')) -- u.meta
print(pattern_matcher("u.meta_something", '^u%.meta%f[%z.]')) -- nil
print(pattern_matcher("u.meta-something", '^u%.meta%f[%z.]')) -- nil

Solution

  • If you need to support user input as a literal part of a regex pattern, you need to introduce an escaping function so that all magic characters were escaped with %. Then, just concatenate with the custom boundaries (^ start of string, and %f[%z.] for the end of string or a dot).

    function escape (s)
          return string.gsub(s, '[.*+?^$()[%%-]', "%%%0")
    end
    function pattern_matcher(v, pattern) return string.match(v, pattern) end
    
    word = "u.meta"
    print(pattern_matcher("u.meta.something", '^' .. escape(word) .. '%f[%z.]')) -- u.meta
    

    See this demo

    In the escape function, the first two %% in the replacement pattern denote one %, and %0 backreferences the whole match (one of the magic characters)