Posted 07 August 2014 - 07:50 PM
Hey gang, I haven't really been active lately, but I started working on some new stuff for myself and had to find a solution for a problem for which I couldn't seem to find a work around. This problem was that while trying to match patterns, I wanted to know where in the string that a match was showing up.
To solve this problem, I wrote an iterator function which uses a combination of string.gmatch and string.find to match all occurrences while also keeping track of where the match comes from in the string.
This function returns both the start and stop of the match as well as the match itself. This was one of my first experiences writing an iterator function, but I hope it works well for anyone else who might need something like this! :)/>
Example:
You guys are welcome to use it, but, if you wouldn't mind, please give credit where credit is due. :)/>
Pastebin.
To solve this problem, I wrote an iterator function which uses a combination of string.gmatch and string.find to match all occurrences while also keeping track of where the match comes from in the string.
--[[
This function behaves just like gmatch, but it also returns the position
in the line of the match.
@return iterator function which returns the start, stop, and textual match of every
occurence of the given pattern.
Example:
for start, stop, match in gfind (str, pat) do
...
end
]]
local function gfind (_string, pattern)
if not _string or not pattern then
error ("Arguments to gfind are invalid: faulty string or pattern.")
end
local start, stop;
return function()
if stop then
stop = stop + 1
end
start, stop = _string:find (pattern, stop)
return start, stop, (start ~= nil) and _string:sub (start, stop) or nil
end
end
This function returns both the start and stop of the match as well as the match itself. This was one of my first experiences writing an iterator function, but I hope it works well for anyone else who might need something like this! :)/>
Example:
local function gfind (_string, pattern)
if not _string or not pattern then
error ("Arguments to gfind are invalid: faulty string or pattern.")
end
local start, stop;
return function()
if stop then
stop = stop + 1
end
start, stop = _string:find (pattern, stop)
return start, stop, (start ~= nil) and _string:sub (start, stop) or nil
end
end
local _string = "This is a string with with a repeat in it."
local lastWord;
for start, stop, match in gfind (_string, "%s-(%w+)%s-") do
if match == lastWord then
_string = _string:sub (1, start - 1) .. _string:sub (stop + 1)
end
lastWord = match
end
-- Output: This is a string with a repeat in it.
print (_string)
The above example, although probably not that common of an issue and one with more than one solution, goes through the string and locates repeated words which are right next to one another. By using gfind, we can remove the repeated word. However, this is obviously not the best example because there are sentences in English where words are repeated simultaneously for necessity, such as "that that," but I couldn't think of another example quickly off the top of my head which did not require a lot of background (I am using this function in a larger script).You guys are welcome to use it, but, if you wouldn't mind, please give credit where credit is due. :)/>
Pastebin.