Search code examples
lualua-patternsworld-of-warcraft

Lua Patterns - World of Warcraft Vanilla


I'm trying to get some data from the chat of the game but I can't figure out the pattern.

It's for an AddOn for a World of Warcraft Vanilla (private server).

gsub function:
http://wowprogramming.com/docs/api/gsub
http://wowwiki.wikia.com/wiki/API_gsub

I have been doing well with this explanation but now there's a part where I have something like this:

variable = gsub(string, "([%d+d]+)?...", "")

I don't know what the pattern should be since the string can be like one the following examples:

2d17h6m31s
1d8h31m40s
22h40m4s
8h6m57s
5m25s
37s

The "([%d+d]+)?" is actually multiple attempts of mine put in together.

I did read about the magic characters ( ) . % + - * ? [ ^ $ but there's still some that I don't understand. If I could get a simple resume explanation it would be great!

The important part of how the chat looks like:

chat

Edit (ktb's comment):

Question: How can I take the full "99d23h59m59s" (^(.*s) didn't did the trick)?

In 99d23h59m59s, the 99 can be from 1 to 99 and it always has a d right after but it's optional if there's actually a <number>d or not. Then the same to <number>h (number's range goes from 1 to 24), <number>m (number's range goes from 1 to 59). There's always a ago in the end.

Update:

/run for key in pairs(string)do ChatFrame1:AddMessage(key)end

With that command I got all the functions's names of string.functionName(), here's the list:

string.sub()

string.gfind()

string.rep()

string.gsub()

string.char()

string.dump()

string.find()

string.upper()

string.len()

string.format()

string.byte()

string.lower()

Information update:

Unlike several other scripting languages, Lua does not use POSIX regular expressions (regexp) for pattern matching. The main reason for this is size: A typical implementation of POSIX regexp takes more than 4,000 lines of code. This is bigger than all Lua standard libraries together. In comparison, the implementation of pattern matching in Lua has less than 500 lines. Of course, the pattern matching in Lua cannot do all that a full POSIX implementation does. Nevertheless, pattern matching in Lua is a powerful tool and includes some features that are difficult to match with standard POSIX implementations.

Source.

Unlike some other systems, in Lua a modifier can only be applied to a character class; there is no way to group patterns under a modifier. For instance, there is no pattern that matches an optional word (unless the word has only one letter). Usually you can circumvent this limitation using some of the advanced techniques that we will see later.

Source.

I can't find the "advanced techniques" told in the quote above. I only found this which I'm not sure yet.


Solution

  • I ran into the same pattern limitations several years ago with a WoW addon. It took a bit of searching, but I dug up my parsing function.

    parse_duration.lua

    --
    -- string:parseDuration() - parse a pseudo ISO-8601 duration of the form
    -- [nd][nh][nm][ns], where 'n' is the numerical value of the time unit and
    -- suffix designates time unit as follows: 'd' - days, 'h' - hours,
    -- 'm' - minutes, and, 's' - seconds. Unspecified time units have a value
    -- of 0.
    --
    
    function string:parseDuration()
      local ts = {d=0, h=0, m=0, s=0}
      for v in self:lower():gfind("%d+[dhms]") do
        ts[v:sub(-1)] = tonumber(v:sub(1,-2))
      end
    
      return ts
    end
    

    The following tests your sample data.

    duration_utest.lua

    require "parse_duration"
    
    local function main()
      local testSet = {
        "2d17h6m31s ago something happened",
        "1d8h31m40s ago something happened",
        "22h40m4s ago something happened",
        "8h6m57s ago something happened",
        "5m25s ago something happened",
        "37s ago something happened",
        "10d6s alias test 1d2h3m4s should not be parsed"
      }
    
      for i,testStr in ipairs(testSet) do
        -- Extract timestamp portion
        local tsPart = testStr:match("%S+")
        local ts = tsPart:parseDuration()
    
        io.write( tsPart, " -> { ")
        for k,v in pairs(ts) do
          io.write(k,":",v," ")
       end
        io.write( "}\n" )
      end
    end
    
    main()
    

    Results

    2d17h6m31s -> { m:6 d:2 s:31 h:17 }
    1d8h31m40s -> { m:31 d:1 s:40 h:8 }
    22h40m4s -> { m:40 d:0 s:4 h:22 }
    8h6m57s -> { m:6 d:0 s:57 h:8 }
    5m25s -> { m:5 d:0 s:25 h:0 }
    37s -> { m:0 d:0 s:37 h:0 }
    10d6s -> { m:0 d:10 s:6 h:0 }