Case insensitive array in Lua
I'm trying to program an addon for WoW (in lua). It's a chat filter based on specific words. I can't figure out how to get the array of these words to be case insensitive, so that any upper/lower case combination of the word matches the array. Any ideas would be greatly appreciated. Thanks!
local function wordFilter开发者_开发知识库(self,event,msg)
local keyWords = {"word","test","blah","here","code","woot"}
local matchCount = 0;
for _, word in ipairs(keyWords) do
if (string.match(msg, word,)) then
matchCount = matchCount + 1;
end
end
if (matchCount > 1) then
return false;
else
return true;
end
end
Use if msg:lower():find ( word:lower() , 1 , true ) then
==> it lower cases both of the arguments to string.find: hence case insensitivity. Also I used string.find because you probably want the 'plain' option, which doesn't exist for string.match.
Also you can easily return on the first word found:
for _ , keyword in ipairs(keywords) do
if msg:lower():find( keyword:lower(), 1, true ) then return true end
end
return false
- Define keyWords outside of function. Otherwise you're recreating table every time just to thorw it away moments latter, wasting time on both creation and GC.
- Convert keyWords to patter that match both upper and lower case letters.
- You don't need captured data from string, so use string.find for speed.
- According to your logic, if you've got more than one match you signal 'false'. Since you need only 1 match, you don't need to count them. Just return false as soon as you hit it. Saves you time for checking all remaining words too. If later you decide you want more than one match, you still better check it inside loop and return as soon as you've reached desired count.
Don't use ipairs. It's slower than simple for loop from 1 to array length and ipairs is deprecated in Lua 5.2 anyway.
local keyWords = {"word","test","blah","here","code","woot"} local caselessKeyWordsPatterns = {} local function letter_to_pattern(c) return string.format("[%s%s]", string.lower(c), string.upper(c)) end for idx = 1, #keyWords do caselessKeyWordsPatterns[idx] = string.gsub(keyWords[idx], "%a", letter_to_pattern) end local function wordFilter(self, event, msg) for idx = 1, #caselessKeyWordsPatterns do if (string.find(msg, caselessKeyWordsPatterns[idx])) then return false end end return true end local _ print(wordFilter(_, _, 'omg wtf lol')) print(wordFilter(_, _, 'word man')) print(wordFilter(_, _, 'this is a tEsT')) print(wordFilter(_, _, 'BlAh bLAH Blah')) print(wordFilter(_, _, 'let me go'))
Result is:
true
false
false
false
true
You can also arrange this with metatables, in an entirely transparent way:
mt={__newindex=function(t,k,v)
if type(k)~='string' then
error'this table only takes string keys'
else
rawset(t,k:lower(),v)
end
end,
__index=function(t,k)
if type(k)~='string' then
error'this table only takes string keys'
else
return rawget(t,k:lower())
end
end}
keywords=setmetatable({},mt)
for idx,word in pairs{"word","test","blah","here","code","woot"} do
keywords[word]=idx;
end
for idx,word in ipairs{"Foo","HERE",'WooT'} do
local res=keywords[word]
if res then
print(("%s at index %d in given array matches index %d in keywords"):format(word,idx,keywords[word] or 0))
else
print(word.." not found in keywords")
end
end
This way the table can be indexed in whatever case. If you add new words to it, it will automatically lower-case them too. You can even adjust it to allow matching with patterns or whatever you'd like.
精彩评论