Searching for a defined set of values in a string

Viewed 49

I'm trying to search a string for a set of values and return the value ONLY if the string matches exactly with one of the set.

My original expression was as so:

title = "MrS"
setTitles = {"Miss", "Mr", "Mrs", "Dr", "Ms"}
title = (title:gsub("%w",string.lower)):gsub("^l", string.upper)

if string.match(title, setTitles) ~= nil then title = title else title = "XX" end

I then realised I needed some way of cycling through the values so got to here:

title = "MrS"
setTitles = {"Miss", "Mr", "Mrs", "Dr", "Ms"}
title = (title:gsub("%w",string.lower)):gsub("^%l", string.upper)

for i = 1, 5 do
  if string.match(title, setTitles[i]) ~= nil 
    then title = title 
  else title = "XX" 
  end
end

Except that just returns "XX" every time.

I know it's probably quite simple and obvious, but I can't seem to find a solution and would really appreciate a hand!

2 Answers

Here is why your code is not working. Your first iteration of the loop uses Mrs and checks if it matches Miss, and it does not so it changes title to XX and thus no following checks can ever match.

You cant change title until you have checked all your possible values first. By adjusting your code to use a matchFound variable to determine if the change is needed you can fix this problem:

local matchFound = false
for i = 1, 5 do
  if string.match(title, setTitles[i]) ~= nil then
    matchFound = true
    break
  end
end
if matchFound == false then
  title = "XX"
end
print(title)

Additionally your code can give false matches for Mr rather then Mrs this is because Mr will match inside Mrs or any string that starts with Mr. To change this you can adjust your call of string.match to:

string.match(title, "^".. setTitles[i] .. "$")

This forces string.match to insure that the first and last chars of the pattern are also the first and last chars of the string passed to it.


As a suggestion, Rather then using string.match, make your setTitles a proper set like:

local setTitles = {["Miss"] = true, ["Mr"] = true, ["Mrs"] = true, ["Dr"] = true, ["Ms"] = true}

Then your check becomes:

title = setTitles[title] and title or "XX"

Lua resource on Sets:

https://www.lua.org/pil/11.5.html

http://lua-users.org/wiki/SetOperations

You shouldn't change the title variable in the for loop.

You can try this code:

--title = "MrS"
title = "MrX"
setTitles = {"Miss", "Mr", "Mrs", "Dr", "Ms"}
title = title:gsub("%w", string.lower) -- mrs
title = title:gsub("^%l", string.upper) -- Mrs

ismatch = false

for i = 1, 5 do

    print(title, setTitles[i])

    if tostring(title) == tostring(setTitles[i]) then
        ismatch = true
        print("matched")
        return
    end

end

if ismatch then title = title else title = "XX" end
print(title)

Hope this helps.

Related