4

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.

Community
  • 1
  • 1
user7393973
  • 2,270
  • 1
  • 20
  • 58
  • It seems that every one of those potential patterns ends with `s ago` so why not match that? `"^(.*s) ago"`. Also you might want to use `match` instead of `gsub`. If you need a regex to split the strings into fields, then reformat your question and I'll give a proper answer. – ktb Feb 10 '17 at 21:30
  • @ktb, now that you say that, I probably don't mind getting the whole "99d23h59m59s". Not sure if `match` works on the game tough, I have tried some of the string functions and the only ones I found working was `gsub` and `strfind`. If you do think it should work, give me the function's name because I don't think "[match](http://i.imgur.com/HLeuEeM.png)" works. – user7393973 Feb 10 '17 at 21:39
  • I was unfamiliar with the modifications to the base language WoW added. They added non-namespaced aliases for certain functions. For example, `gsub` is really an alias for `string.gsub`, as well as `strmatch` being an alias for `string.match`, which is the function I was referring to. And I believe you might need to edit your question to explain *exactly* what you want to match from those strings. From your example, I am inferring that you are trying to match the day portion of the string? – ktb Feb 10 '17 at 21:48
  • @ktb, question edited in the end. – user7393973 Feb 10 '17 at 22:15
  • That wiki you linked has an entire article about Pattern Matching, I reference it all the time myself. http://wowwiki.wikia.com/wiki/Pattern_matching Explains well what the magic characters do. – Alundaio Feb 11 '17 at 00:59
  • @Alundaio - Yes, I'm trying to learn it all now. Also checking [this](http://lua-users.org/wiki/PatternsTutorial) and [this](https://www.lua.org/manual/5.3/manual.html#6.4.1). It's just a little to much information to absorve and a bit confusing but I'm doing my best to understand it. – user7393973 Feb 11 '17 at 01:02

2 Answers2

4
function get_time_stamp(str)
    local s,m,h,d = string.match(str:reverse(),"oga s(%d*)m?(%d*)h?(%d*)d?(%d*)")
    return d and d:reverse() or 0, h and h:reverse() or 0, m and m:reverse() or 0, s and s:reverse() or 0
end 
local day,hour,minute,second = get_time_stamp("2d17h6m31s ago")
print (day,hour,minute,second) -- output: 2 17 6 31

day,hour,minute,second = get_time_stamp("5m25s ago")
print (day,hour,minute,second) -- output: 0 0 5 25

If you are wondering why I use reverse, it's because we know for sure second will always exist but the others won't, if we don't use reverse then we won't know what order the numbers are in when output by string.match. Here is example what I mean, if you did local d,h,m,s = string.match("5m25s ago","(%d*)d?(%d*)h?(%d*)m?(%d+)s ago") Then print(d,h,m,s) would say that days was 5 and seconds were 25. In reverse we know with absolute certainty the order of output.

Alundaio
  • 551
  • 4
  • 8
  • That may be a way to make it work, but right now I'm to focused in learning if I can use the patterns and captures to have optional substrings. – user7393973 Feb 11 '17 at 01:46
  • @user7393973 Unfortunately, Lua's patterns do not support what I think you want. This is a good place to start with patterns in Lua https://www.lua.org/manual/5.1/manual.html#5.4.1 – ktb Feb 11 '17 at 02:45
  • @user7393973 Edited, the solution might be more suitable for your needs. A single pattern match. – Alundaio Feb 11 '17 at 03:21
2

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 }
Frelling
  • 3,287
  • 24
  • 27