4
function msgcontains(msg, what)
    msg = msg:lower()

    -- Should be replaced by a more complete parser
    if type(what) == "string" and string.find(what, "|", 1, true) ~= nil then
        what = what:explode("|")
    end

    -- Check recursively if what is a table
    if type(what) == "table" then
        for _, v in ipairs(what) do
            if msgcontains(msg, v) then
                return true
            end
        end
        return false
    end

    what = string.gsub(what, "[%%%^%$%(%)%.%[%]%*%+%-%?]", function(s) return "%" .. s end)
    return string.match(msg, what) ~= nil
end

This function is used on a RPG server, basically I'm trying to match what the player says

e.g; if msgcontains(msg, "hi") then

msg = the message the player sent

However, it's matching anything like "yesimstupidhi", it really shouldn't match it because "hi" isn't a single word, any ideas what can I do? T_T

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Raúl Sanpedro
  • 266
  • 4
  • 15

3 Answers3

4

Frontiers are good for dealing with boundaries of the pattern (see Lua frontier pattern match (whole word search)) and you won't have to modify the string:

return msg:match('%f[%a]'..what..'%f[%A]') ~= nil

The frontier '%f[%a]' matches only if the previous character was not in '%a' and the next is. The frontier pattern is available since 5.1 and official since 5.2.

Community
  • 1
  • 1
ryanpattison
  • 6,151
  • 1
  • 21
  • 28
1

You can use a trick mentioned by Egor in his comment, namely: add some non-word characters to the input string, and then enclose the regex with non-letter %A (or non-alphanumeric with %W if you want to disallow digits, too).

So, use

return string.match(' '..msg..' ', '%A'..what..'%A') ~= nil

or

return string.match(' '..msg..' ', '%W'..what..'%W') ~= nil

This code:

--This will print "yes im stupid hi" since "yes" is a whole word
msg = "yes im stupid hi"
if msgcontains(msg, "yes") then
    print(msg)
end
--This will not print anything
msg = "yesim stupid hi"
if msgcontains(msg, "yes") then
    print(msg)
end

Here is a CodingGround demo

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

Just think about "what's a word". A word has specific characters in front and behind it, like whitespaces (space, tabulator, newline, carriage return, ...) or punctation (comma, semicolon, dot, line, ...). Furthermore a word can be at the text begin or end.

%s, %p, ^ and $ should interest you.

For more, see here.

Youka
  • 2,646
  • 21
  • 33