Raúl Sanpedro
Raúl Sanpedro

Reputation: 366

Trying to check if a string contains a given word

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

Upvotes: 4

Views: 8513

Answers (3)

ryanpattison
ryanpattison

Reputation: 6251

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.

Upvotes: 4

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627536

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

Upvotes: 1

Youka
Youka

Reputation: 2715

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.

Upvotes: 0

Related Questions