[Home] [Downloads] [Search] [Help/forum]

Gammon Forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  General
. . -> [Subject]  Multiline trigger with variable length
Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

Multiline trigger with variable length

You need to log onto the forum to reply or create new threads.

  [Refresh] Refresh page


Posted by Nisin   (4 posts)  [Biography] bio
Date Wed 29 Nov 2017 04:16 AM (UTC)
Message
Hello,
I've read a bit about multiline triggers on here and understand (And have experienced) the pain they can be. I am trying to capture "items" to then be processed via a script. THe description of these items can be variable length. The other challenge is the MUD supplies the line breaks, there is no option to not break or a setting or anything.

As an example, here is some output:

[*][SAFE]<3010hp 3286sp 2356st> 
look key

You focus your powers of observation on a porcelain key:
Item 'a porcelain key' is type key, alignment 0, made of stone (in (new) condition),
has keywords 'porcelain key'.
This item weighs 0 stones and 4 pebbles, and is valued at 10 gold. {Cat. 0}
This level 0 item has the attributes: no-auction
This key may be used 1 more time.
*This item may be repaired 8 times.
*A porcelain key will last approximately 850 more Alyrian minutes.
This is a key that opens some sort of lock somewhere in the Ithrilis
temple of Xaventry.  Not knowing what door the key opens doesn't help you
very much.  Perhaps one of the clergy of the temple can help you find the
door it matches.  

[*][SAFE]<3010hp 3286sp 2356st> 


Now I have been able to get this mostly working using the following trigger:

<triggers>
  <trigger
   group="itemCapture"
   lines_to_match="15"
   keep_evaluating="y"
   match="^You focus your powers of observation on (.+):\nItem '(?P&lt;itemName&gt;.+)' is type (.+), alignment ([\-0-9]+), made of (.+) \(in \((.+)\) condition\),\nhas keywords '(.+)'\.\nThis item weighs ([0-9]+) stones and ([0-9]+) pebbles, and is valued at ([0-9]+) gold\. \{Cat. [0-9]\}\nThis level ([0-9]+) item has the attributes: (.+)\n(This key may be used ([0-9]+ more time(|s)|an unlimited number of times))\.\n\*This item may be repaired (?P&lt;repairCount&gt;[0-9]+) times\.\n((?P&lt;itemDescr&gt;.*)\n)+\n$"
   multi_line="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
ColourNote("silver", "black", "found item:")
ColourNote("silver","black","%&lt;itemName&gt;")
  </trigger>
</triggers>



I basically set the lines to trigger to be a high number. The problem is, this has the potential to over capture at times, and if I simply send a blank line and get a new prompt back from the MUD, it results in the same trigger matching again. This wouldn't be a big deal, except that it keeps capturing the additional lines, when it should be breaking before the next prompt. There is a \n\n there, but each time I've tried putting that in at the end of my trigger match, the regex then seems to fail.

What am I missing here, or is there a better way of doing this when there could be variable length and count of lines?

Thanks in advance!
[Go to top] top

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #1 on Wed 29 Nov 2017 04:21 AM (UTC)

Amended on Wed 29 Nov 2017 04:22 AM (UTC) by Nick Gammon

Message
That is exactly what multiline triggers will do if you don't "anchor" them. Try putting \z at the end of the regexp rather than $. The \z specifies "end of subject" so that will only apply when the matching text is at the end of the output window (and not when it scrolls up a line).

Alternatively see:

Template:faq=37 Please read the MUSHclient FAQ - point 37.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nisin   (4 posts)  [Biography] bio
Date Reply #2 on Wed 29 Nov 2017 11:52 AM (UTC)
Message
I forgot to include, i have tried using the \a and \z at the beginning and end to set the positional requirements. as soon as i add those though it stops working at all.

example

You focus your powers of observation on (.+):\nItem '(?P<itemName>.+)' is type (.+), alignment ([\-0-9]+), made of (.+) \(in \((.+)\) condition\),\nhas keywords '(.+)'\.\nThis item weighs ([0-9]+) stones and ([0-9]+) pebbles, and is valued at ([0-9]+) gold\. \{Cat. [0-9]\}\nThis level ([0-9]+) item has the attributes: (.+)\n(This key may be used ([0-9]+ more time(|s)|an unlimited number of times))\.\n\*This item may be repaired (?P<repairCount>[0-9]+) times\.\n(?P<itemDescr>.*)\n\n\z


I was thinking it was failing perhaps because the double new line at the end to capture the blank like before the prompt was breaking it, but it doesn't seem to be, even if i take that out.
[Go to top] top

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #3 on Wed 29 Nov 2017 11:51 PM (UTC)
Message
This seems to work on your test data:


<triggers>
  <trigger
   enabled="y"
   group="itemCapture"
   lines_to_match="15"
   keep_evaluating="y"
   match="^You focus your powers of observation on (.+):\nItem '(?P&lt;itemName&gt;.+)' is type (.+), alignment ([\-0-9]+), made of (.+) \(in \((.+)\) condition\),\nhas keywords '(.+)'\.\nThis item weighs ([0-9]+) stones and ([0-9]+) pebbles, and is valued at ([0-9]+) gold\. \{Cat. [0-9]\}\nThis level ([0-9]+) item has the attributes: (.+)\n(This key may be used ([0-9]+ more time(|s)|an unlimited number of times))\.\n\*This item may be repaired (?P&lt;repairCount&gt;[0-9]+) times\.\n((?P&lt;itemDescr&gt;.+)\n)\Z"
   multi_line="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
ColourNote("gold", "black", "found item:")
ColourNote("gold","black","%&lt;itemName&gt;")
</send>
  </trigger>
</triggers>



Template:pasting For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.


I think your problem with your original regexp was this bit:


\n((?P<itemDescr>.*)\n)+


That is basically saying that the item description can be one or more occurrences of any data. Thus all the lines following the item description matched it.

I've added in a \Z and got rid of the last "+".

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nisin   (4 posts)  [Biography] bio
Date Reply #4 on Fri 01 Dec 2017 03:44 AM (UTC)
Message
Thanks for this, you are a great help! I was able to further extend it to capture the multiple lines, which was the original intent.

I am a little fuzzy on the starting the expression with ^ and ending with the \Z rather than starting with a \A or ending with a $, feels odd mixing those...but it seems to work! :)

One other question that I seem to be missing. When I capture multiple lines they clearly have a line break in the description (hence why we are doing the multiline capture). When I try using this in a script, it ends up breaking because the string isn't "terminated". An example follows.


local mystr = "this is some string
that is broken on two lines"

ColourNote("gold","Black", mystr)

Compile error
World: MyWorld
Immediate execution
[string "Trigger: "]:4: unfinished string near '"this is some string'


So how do I get it to read those line breaks as \n in a string? I am accessing it using the %itemDescr wildcard since that is a named group in the expression. I feel like I need to replace something with a \n but that is already is what is since regex is matching it.

Maybe this isn't possible in a basic trigger script action and I have to do it in an actual script/plugin?
[Go to top] top

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #5 on Fri 01 Dec 2017 04:02 AM (UTC)
Message
In Lua multi-line strings are delimited by square brackets like this:


local mystr = [[this is some string
that is broken on two lines]]

ColourNote("gold","Black", mystr)


In your trigger you would need to put the "capture" inside the double square brackets to achieve the same effect.

You might conceivably have trouble if the matching text had square brackets in it (this may never happen if the regexp doesn't allow it).

You could use a script file rather than "send to script" because then the wildcards are already put into variables and you don't have the issue of treating them like literal strings.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nisin   (4 posts)  [Biography] bio
Date Reply #6 on Tue 05 Dec 2017 10:04 PM (UTC)
Message
Thanks Nick!

As I keep fiddling with it I found another snag I can't seem to work around.

https://regex101.com/r/bZaZfp/4

That has my example and the pattern I've been able to get working. However when I put it in the client, I believe I still have to check the multiline box and give it a "window" but then I get the multiple triggers again for the same result even though the client only shows it once.

What am I missing or not understanding fundamentally about how multiline works within a trigger and when used as a regex expression?
[Go to top] top

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #7 on Tue 05 Dec 2017 11:00 PM (UTC)
Message
The regex101.com does a single match, and therefore naturally each match is only returned once. MUSHclient does a match per line from the MUD and the multi-line triggers therefore potentially overlap with the previous match.

For example, if you matched on:


^foo\n(bar\n)+\Z


And if you got this from the MUD:


foo
bar
bar
bar
bar


It will match four times, first on foo/bar then foo/bar/bar then foo/bar/bar/bar and so on.

You need to have something at the end which indicates that the matching is over. For example:


^foo\n(bar\n)+fubar\Z


That final "fubar" has to be there, and therefore it will only match once, assuming you send down:



foo
bar
bar
bar
bar
fubar


The first few lines (which only end in "bar") don't satisfy the regexp because it hasn't seen "fubar".

Now in your case you need something to indicate the end of the item attributes (for example, a blank line).

Even that could fail if you subsequently get a second blank line. It's the nature of repetitively applying a regexp to the same string, where that string gets longer and longer.

One of your problems is that your match is for anything and therefore things like prompt lines also satisfy the match.

The suggestion I made above about FAQ #37 is probably the best way of solving it. You make three triggers:


  1. Match on "^You focus your powers of observation on". Turn on triggers #2 and #3
  2. Match on end of description (eg. a blank line). Turn off triggers #2 and #3. Return (print or save) the results (saved by trigger #3)
  3. Match on anything (this is lower priority than trigger #2). Save the matching line in a table for when we reach the end of the description

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #8 on Tue 05 Dec 2017 11:49 PM (UTC)

Amended on Tue 05 Dec 2017 11:50 PM (UTC) by Nick Gammon

Message
Just to clarify a bit, multi-line triggers are fine for things with a well-defined structure, for example:


You focus your powers of observation on an obsidian key:
Item 'an obsidian key' is type key, alignment 0, made of obsidian
This item weighs 0 stones and 0 pebbles, and is valued at 10 gold.
This level 0 item has the attributes: no-auction
This key may be used 1 more time.


You could make a multi-line trigger:


^You focus your powers of observation on .+
Item '.+?' is type .+?, alignment .+?, made of .+?
This item weighs \d+ stones and \d+ pebbles, and is valued at \d+ gold\.
This level \d+ item has the attributes: .*?
This key may be used \d+ more time\.\Z


(Assuming we have \n at the end of each line)

Now in this case we have a well-defined structure to what we are expecting, and it will match when we get that and only that. The \Z at the end makes sure we only match when we first see it and not subsequently.

However once you try to match something followed by an indefinite number of free-format lines, then there is the potential for other stuff arriving later (eg. prompts, chats) to be considered part of the item, and also for the match to be made prematurely. For example, how do you know after getting 5 free-format lines if there is going to be a 6th?

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


719 views.

You need to log onto the forum to reply or create new threads.

  [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at FutureQuest]