String.gmatch help (i think)

Posted by KripsiKreme on Sat 12 Sep 2009 10:11 AM — 9 posts, 37,004 views.

#0
For awhile now i've been trying to built a plugin that changes a block of written text over to an ascii in a miniwindow or an ascii map in the output, so i can have both the written text to see who is in what direction, and to be able to see a map of where everything is for ease on the eyes. I'm fairly sure i can do most of it, but it's taking the string and storing it as useful data i'm finding hard, and think string.gmatch is the way to do it, but can't seem to make it work.

Example text it would trigger off:

A door west of here, an exit west of here, Kilstrin Mortificer is one east, a door south of one east, an exit south of one east, an exit southwest of one east, an exit west of one east and the limit of your vision is one east from here.

i'd like it to make tables of where the doors, exits and people are, but can't seem to make it work. not really much script to show as i've mostly been fiddling and not getting anywhere, but what i have is:

function test (name, line, wildcards)
exits = {}
exits.here = {string.match(line, "exit (.*) of here")}
for k, v in pairs (exits.here) do
print("key: ", k, " value: ", v)
end -- for
end -- test

output:

key: 1 value: west

which works for when "an exit (.*) of here" occurs once in a line, but doesn't fire at all if it has a second match in the line or store them to the table, then i found the stuff about string.gmatch working to do pretty much that (http://www.gammon.com.au/forum/?id=6034), but can't seem to make it work. any suggestions or hints as to what i'm doing wrong? I'm fairly new to all this stuff.

Thanks, K
USA #1
Personally, I would start by breaking that insane string into separate lines. That way you can perform individual operations grabbing exits, then doors, then anything left over should be a player/mob.


> test = "A door west of here, an exit west of here, Kilstrin Mortificer is one
east, a door south of one east, an exit south of one east, an exit southwest of
one east, an exit west of one east and the limit of your vision is one east from
 here."
> for i in string.gmatch(test, "%s?([^,]*)" ) do print(i) end
A door west of here

an exit west of here

Kilstrin Mortificer is one east

a door south of one east

an exit south of one east

an exit southwest of one east

an exit west of one east and the limit of your vision is one east from here.


edit: Some day I will be able to post code directly out of a console correctly on the first try!
Amended on Sat 12 Sep 2009 05:26 PM by Shaun Biggs
Australia Forum Administrator #2
I am inclined to agree with Shaun that it is better to start breaking up the larger problem into smaller ones. Without doing that, you can see problems:


function test (name, line, wildcards)
  exits = {}

  for exit in string.gmatch (line, "exit (%a-) of here") do
    exits [exit] = true
  end -- for

  tprint (exits)
end -- test


test ("blah", [[A door west of here, an exit west of here, 
Kilstrin Mortificer is one east, 
a door south of one east, an exit south of one east, 
an exit southwest of one east, 
an exit west of one east and the limit of your vision is one east from here.]])


--> Output

"west"=true


There is only one "exit xxx of here", the others are "exit xxx of one xxx", which requires a different match, or "a door xxx of one xxx".

If you adopt Shaun's idea, at least most lines now start with "an exit" or "a door". For those lines you can probably look for the word before "of" and the word or words after "of".

Something along these lines seems to work:



test = [[A door west of here, an exit west of here, 
Kilstrin Mortificer is one east, 
a door south of one east, an exit south of one east, 
an exit southwest of one east, 
an exit west of one east and the limit of your vision is one east from here.]]

exits = {}

test = string.gsub (test, " and ", ", ")

for part in string.gmatch (test, "%s?([^,]*)" ) do 

  exittype = "exit"
  exitline = string.match (part, "^an exit (.*)")

  if not exitline then
    exitline = string.match (part, "^a door (.*)")
    exittype = "door"
  end -- if  

  if exitline then
    exit, where = string.match (exitline, "^(.+) of (.+)$")
    table.insert (exits, { where = where, exit = exit, exittype = exittype })
  end -- if
end

tprint (exits)

--> Output

1:
  "exit"="west"
  "where"="here"
  "exittype"="exit"
2:
  "exit"="south"
  "where"="one east"
  "exittype"="door"
3:
  "exit"="south"
  "where"="one east"
  "exittype"="exit"
4:
  "exit"="southwest"
  "where"="one east"
  "exittype"="exit"
5:
  "exit"="west"
  "where"="one east"
  "exittype"="exit"

Amended on Sat 12 Sep 2009 09:39 PM by Nick Gammon
#3
That's awesome, thank you very much Shaun and Nick =D Pretty sure i'll be able to write a lot of it now by myself once I've learnt more about tables and retrieving data from them, but that's what this is- a big learning project. One last thing though, as i can't find it from fiddling with what you wrote, is there a way you could make it track the living things and where they are in a table too? Kilstrin Mortificer in this example. small note if it helps, they can be any cardinal direction and one or two rooms away.

Thanks again for all the help!

K
Australia Forum Administrator #4
Well, if you don't have exitline then it didn't find "an exit" or "a door" so I would then search for "<someone> is <somewhere>".

Should be pretty easy based on what there is there.
#5
Thanks again, managed to work it out for myself and get it all in there, sort out problems with it. Actually quite proud of the bits i did myself =P

What i can't work out is this, changed the test line to include more people, and added some tables in the tables, but now can't get it to get info from the tables.

test = [[A door west of here, an exit west of here,
Kilstrin Mortificer is one east, a door south of one east,
Pite fhtagn and Chimara R Speshul are one east and one south,
an exit south of one east, an exit southwest of one east,
an exit west of one east and the limit of your vision is one east from here.]]

tprint(exits)

output

"exits":
  1:
    "exit"="west"
    "where"="here"
    "exittype"="exit"
  2:
    "exit"="south"
    "where"="one east"
    "exittype"="exit"
  3:
    "exit"="southwest"
    "where"="one east"
    "exittype"="exit"
  4:
    "exit"="west"
    "where"="one east"
    "exittype"="exit"
"doors":
  1:
    "exit"="west"
    "where"="here"
    "exittype"="door"
  2:
    "exit"="south"
    "where"="one east"
    "exittype"="door"
"living":
  1:
    "exittype"="living"
    "where"="one east"
    "who"="Kilstrin Mortificer"
  2:
    "exittype"="living"
    "where"="one east and one south"
    "who"="Pite fhtagn and Chimara R Speshul"


i can get it to print the above with, "tprint(exits)" just one of the named tables "tprint(exits.doors)" and even one of the numbered tables in that "tprint(exits.doors [1])", but can't get it too print say one entry like the "where" entry, or do anything remotely useful with them. any tips? Ideally like to be able to call up a whole table into like a set of variables or something, and then dostuff() with the data, then move onto the next table.

something like:

1) Get the first numbered exit table,
2) get the data from it into some form of variable, or x = where, y = exittype, z = exit, or something (this is where i'm having trouble)
3) move onto the next numbered table, then finish so i can move it onto doors, then living.
then going to make it (with other map drawing script from from a badly written version of this sort of thing with about a million string.finds() in it and 2 million SetVariable()) draw y in z from x, or prepare it to be drawn in a function, so that in (exits.exits [1]) it would draw an "exit" "west" from the designated "here" point.

So any tips on how to work the data into a way of doing that? Thanks a heap, sorry if this feels like schoolwork to you or anything, i apprieciate that you're doing this for nothing.
Amended on Tue 15 Sep 2009 09:49 PM by KripsiKreme
Australia Forum Administrator #6
With your table, you just iterate through it pulling out the info like this:



for i, exit in ipairs (exits) do
 
  print ("type=", exit.exittype, "exit=", exit.exit, "where=", exit.where)

end -- for

Output -->

type= exit exit= west where= here
type= door exit= south where= one east
type= exit exit= south where= one east
type= exit exit= southwest where= one east
type= exit exit= west where= one east


#7
Hi Nick, I can't seem to make it pull that data out using the ipairs function you gave me, it doesn't output anything. any suggestions as to why this is? i've fiddled abit and can get outputs like:

for i, exit in ipairs (exits.exits) do
  print ("type=", exits.exittype, "exit=", exits.exits, "where=", exits.where)
end -- for

Output -->

type= nil exit= table: 04D5C928 where= nil
but nothing else seems to match or output the table.

thanks, K.
Australia Forum Administrator #8
I had "ipairs (exits)" not "ipairs (exits.exits)".

It is hard to say what you have done without seeing more of it.