3

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
Community
  • 1
  • 1
przbadu
  • 5,769
  • 5
  • 42
  • 67

2 Answers2

1

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)

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
1

Here is my final solution:

-- USAGE:
--
--  local t     = {}
--  t['roles']  = 'u.meta.admin'
--  match_roles(t, 'u.meta') -- u.meta
--  match_roles(t, 'u.fake') -- nil
--
-- SOLUTION 1
--------------
--
-- function u_meta(v) return string.match(v, '^u%.meta%f[%z.]') end
-- function u_domain(v) return string.match(v, '^u%.domain%f[%z.]') end
-- 
-- function match_roles(table, pattern)
--   for _, value in pairs(table) do
--     if pattern == "u.meta" then
--       if pattern == u_meta(value) then return true end
--     elseif pattern == "u.domain" then
--       if pattern == u_domain(value) then return true end
--     end
--     return false
--   end
-- end

-- SOLUTION 2
---------------
--
-- function pattern_matcher(v, p) return string.match(v, p) end
-- function match_roles(table, role, pattern)
--   for _, value in pairs(table) do
--     if role == pattern_matcher(value, pattern) then return true end
--     return false
--   end
-- end

-- SOLUTIN - 3 (GENERIC SOLUTION) - Thanks Wiktor for pattern
---------------------------------

function escape (s) return string.gsub(s, '[.*+?^$()[%%-]', "%%%0") end
function pattern_matcher(v, pattern) return string.match(v, pattern) end
function match_roles(table, pattern)
  for _, value in pairs(table) do
    if pattern == pattern_matcher(value, '^' .. escape(pattern) .. '%f[%z.]') then return true end
    return false
  end
end


-- UNIT TEST
-- ---------
--
-- Below section covers unit test in lua.
-- we are using `luaunit` unit-testing framework that works for lua.
-- NOTE: LuaUnit works with Lua 5.1, 5.2, 5.3 and luajit (v1 and v2.1),
-- http://luaunit.readthedocs.org/en/latest/
--
package.path = './lib/?.lua;' .. package.path
luaunit = require('luaunit')
local t = {}

function test_meta_user_should_be_true()
  t["roles"] = 'u.meta.admin.system'
  luaunit.assertEquals( match_roles(t, 'u.meta'), true )
end

function test_meta_admin_should_be_true()
  t["roles"] = 'u.meta.admin'
  luaunit.assertEquals( match_roles(t, 'u.meta'), true )
end

function test_system_admin_should_be_true()
  t["roles"] = 'u.meta.admin.system'
  luaunit.assertEquals( match_roles(t, 'u.meta'), true )
end

function test_invalid_meta_admin_should_be_false()
  t["roles"] = 'u.meta_admin'
  luaunit.assertEquals( match_roles(t, 'u.meta'), false )
end

function test_invalid_meta_admin_system_should_be_false()
  t["roles"] = 'u.meta_admin_system'
  luaunit.assertEquals( match_roles(t, 'u.meta'), false )
end

function test_invalid_role_should_be_false()
  t["roles"] = 'u.meta-admin'
  luaunit.assertEquals( match_roles(t, 'u.meta'), false )
end

function test_domain_should_not_allow_in_meta()
  t['roles'] = 'u.domain'
  luaunit.assertEquals( match_roles(t, 'u.meta'), false )
end

function test_domain_user_should_be_true()
  t["roles"] = 'u.domain'
  luaunit.assertEquals( match_roles(t, 'u.domain'), true )
end

function test_domain_admin_should_be_true()
  t["roles"] = 'u.domain.admin'
  luaunit.assertEquals( match_roles(t, 'u.domain'), true )
end

function test_fake_domain_admin_should_be_falsy()
  t["roles"] = 'u.domain_admin'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_fake_role_should_be_falsy()
  t["roles"] = 'u.domain-admin'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_user_should_either_domain_or_meta ()
  t["roles"] = 'u'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_meta_user_in_domain_should_be_false ()
  t["roles"] = 'u.meta'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_meta_admin_in_domain_should_be_false ()
  t["roles"] = 'u.meta.admin'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_system_admin_in_domain_should_be_false ()
  t["roles"] = 'u.meta.admin.system'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_fake_meta_admin_in_domain_should_be_true ()
  t["roles"] = 'u.meta_admin'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_fake_system_admin_in_domain_should_be_true ()
  t["roles"] = 'u.meta_admin_system'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_fake_meta_role_in_domain_should_be_true ()
  t["roles"] = 'u.meta-admin'
  luaunit.assertEquals( match_roles(t, 'u.domain'), false )
end

function test_anything_should_match_correct_pattern()
  t['roles'] = 'a.b.c.z'
  luaunit.assertEquals( match_roles(t, 'a.b'), true )
end

function test_anything_should_fail_incorrect_pattern()
  t['roles'] = 'a.b_c'
  luaunit.assertEquals( match_roles(t, 'a.b'), false )
end

-- Exit after testcases finished
os.exit( luaunit.LuaUnit.run() )
przbadu
  • 5,769
  • 5
  • 42
  • 67