Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ MUSHclient ➜ General ➜ Regular Expression Double Match on Multi-Line Trigger

Regular Expression Double Match on Multi-Line Trigger

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Xavious   (41 posts)  Bio
Date Fri 18 Apr 2014 07:18 PM (UTC)
Message
I have been having a lot of problems creating a multi-line regular expression trigger. The issue surrounds the complicated situation of lines that may or may not be present in the overall expression.

'king crown unique armor' is type armor, extra: rare
This item needs 150000 gold coins before it can be refined.
Armor class is 205. [+197% Enhanced Defense]
This item is covered with razor sharp spikes.
Affects strength by 5.
Affects intelligence by 5.
Affects wisdom by 5.
Affects dexterity by 25.
Affects constitution by 15.
Affects agility by 5.
This item has 525 points of magical resistance.

The line: "This item is covered with razor sharp spikes" may or may not be present on any given item. Example:

'king crown unique armor' is type armor, extra: rare
This item needs 150000 gold coins before it can be refined.
Armor class is 205. [+197% Enhanced Defense]
Affects strength by 5.
Affects intelligence by 5.
Affects wisdom by 5.
Affects dexterity by 25.
Affects constitution by 15.
Affects agility by 5.
This item has 525 points of magical resistance.

My expression is as follows (I inserted newlines for ease of viewing):

Your eyes glow bright yellow for a moment.\n
'(?:king|grandmaster) (?:[a-z]+) ([a-z]+) [a-z ]+' is type (?:[a-z -]+)?( weapon|armor|light), extra: rare\n
This item needs [0-9]+ gold coins before it can be refined.\n
Armor class is [0-9]+. [[0-9+%]+ Enhanced Defense]\n
(?:This (item|weapon) ([a-z ]+).\n)?
Affects strength by [0-9]+.\n
Affects intelligence by [0-9]+.\n
Affects wisdom by [0-9]+.\n
Affects dexterity by [0-9]+.\n
Affects constitution by [0-9]+.\n
Affects agility by [0-9]+.\n
(?:This item has ([0-9]+) points of magical resistance.|\s+)

*Note* The final line was causing me the same problem of double firing, but I found a work around by using "|\s+" because immediately after that line is a blank line. The trigger fires perfectly when the line for the spikes is present. However, if that line is not present it causes the trigger to match two times and I really have no idea why. I also tried "(?:This (item|weapon) ([a-z ]+).\n|\n)?" But it would match twice as well. If that line would only match one of the OR clauses it would be fine, but it matches for both. This project has propelled my regex knowledge quite a ways, however it seems I still have a lot to learn. Any help you guys can offer is greatly appreciated! :D
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #1 on Sat 19 Apr 2014 12:47 AM (UTC)
Message
Personally I wouldn't try to do something that complex with one trigger, but rather with 3 triggers as described here:

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


Next unless we aren't seeing all of your backslashes in the forum post, this is not right:


Armor class is [0-9]+. [[0-9+%]+ Enhanced Defense]\n


Those square brackets that you actually want to match should be escaped, eg.


Armor class is [0-9]+. \[[0-9+%]+ Enhanced Defense\]\n

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Xavious   (41 posts)  Bio
Date Reply #2 on Sat 19 Apr 2014 03:23 AM (UTC)
Message
For whatever reason the forum did, in fact, exclude my forward slash for the enhanced defense part. I actually do have that included in my expression already and the trigger fires perfectly every time, except when the line concerning the spikes is missing.

I'm trying to master regular expressions, so this particular scripting project has become a bit of an obsession for me. If I have to use multiple triggers to accomplish the task I will, but I'm still hoping I can find a way to do it with the multi-line capture. I've stepped through the logic on this trigger several times now and I just can't figure out why it fires twice when that line is missing.

(?:This (item|weapon) ([a-z ]+).\n)?
                                   ^ I thought this was supposed to make this whole group optional. The trigger fires perfectly when this line is here and it fires two times when it isn't.


In any case I appreciate the FAQ reference, Nick. Good to see your still at it man! I think that FAQ already helped me think up a simpler way to accomplish this with multiple triggers, but I'm still interested if I can pull of the complex multi-line trigger as a personal challenge.
You helped me with a regular expression years ago and I still never really understood it until recently. I've reached a part in a programming course that is covering regex, so I was inspired to use it to build a few scripts. I have a way better understanding of them now than I ever did before, but I'm still a newbie :D.
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #3 on Sat 19 Apr 2014 04:13 AM (UTC)
Message
It would help to see your exact trigger (eg. number of lines in the multi-line trigger). Plus, you can "escape" the backslashes, as described here:

Template:copying For advice on how to copy aliases, timers or triggers from within MUSHclient, and paste them into a forum message, please see Copying XML.


One thing you can do to stop multiple matches it to have the very last thing in the trigger by "end of subject" ( \z ) or "end of subject or newline at end" ( \Z ). That will tend to stop multiple matches.

Otherwise with a lot of lines in the multi-line match it can match twice like this:




aaaaaaaaaaaaa
bbbbbbbbbbbbb
ccccccccccccc  <--- first match



aaaaaaaaaaaaa
bbbbbbbbbbbbb
ccccccccccccc  <--- second match
ddddddddddddd 


However with "end of subject" as the last thing it only matches once:



aaaaaaaaaaaaa
bbbbbbbbbbbbb
ccccccccccccc  
ddddddddddddd <--- this is end of subject

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #4 on Sat 19 Apr 2014 04:16 AM (UTC)
Message
Quote:

I thought this was supposed to make this whole group optional.


It does. However the multi-firing is likely to be because of the lack of end of subject in the match.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #5 on Sat 19 Apr 2014 04:21 AM (UTC)

Amended on Sat 19 Apr 2014 04:23 AM (UTC) by Nick Gammon

Message
To explain a bit more, if you have a 10-line multi-line trigger, then MUSHclient gathers up the most recent 10 lines (every time a new line arrives) and submits them to the regexp matcher. Thus it is quite possible for a multiple match to occur.

These 10 lines are the "subject" (of the match). eg.


aaa
bbb
ccc
ddd
eee
fff
ggg
hhh
iii
jjj


Each line has a newline at the end, however the last line (the "jjj" one) is the only one which is the end of subject.

So if you have a definite thing which is always at the end, eg.


This item has xxx points of magical resistance.


Then this is a good thing to have "end of subject" match at the end. That way it only matches if it is at the "jjj" position and not if it ripples up due to extra lines arriving.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Xavious   (41 posts)  Bio
Date Reply #6 on Sun 20 Apr 2014 01:30 AM (UTC)
Message
Thanks for the in depth explanation Nick. I tried using the end of subject match, but it didn't seem to help with the problem. It could possibly be due to the fact that the last line of the trigger is optional as well.

I have found a workaround for my problem by being more picky about what EQ I loot using an in game mechanic called a junk filter. Previously I wanted to be able to filter between the top two tier items, Grandmaster and King. However, I decided to just limit it to the very top tier. By doing this I guarantee all lines will be present, thus ensuring it fires properly each time. King level EQ is never missing magic resistance or spikes. This is, however, a slight loss because occasionally a Grandmaster piece can be perfect. This scenario is pretty rare, though, so it's not that huge of a loss. In fact I have only heard it can be perfect, I have yet to witness it personally. That was my motivation for keeping it open.

Anyway my original script, for reference, was this:

<triggers>
  <trigger
   enabled="y"
   lines_to_match="12"
   match="Your eyes glow bright yellow for a moment.\n'(?:king|grandmaster) (?:[a-z]+) ([a-z]+) [a-z ]+' is type (armor|light), extra: rare\nThis item needs [0-9]+ gold coins before it can be refined.\n(?:Armor class is [0-9]+. [[0-9+%]+ Enhanced Defense]\n)?(?:This item ([a-z ]+).\n)?(?:Affects hit'n'dam by [0-9]+.\n)?Affects strength by [0-9]+.\nAffects intelligence by [0-9]+.\nAffects wisdom by [0-9]+.\nAffects dexterity by [0-9]+.\nAffects constitution by [0-9]+.\nAffects agility by [0-9]+.\n(?:This item has ([0-9]+) points of magical resistance.|\s)"
   multi_line="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>world.note "%1"
world.note "%2"
world.note "%3"
world.note "%4"
if "%3" = "is covered with gruesome spikes" and "%4" = "1050" then
   world.send "put '%1' perfect"
   count = count + 1
   world.note count &amp; " perfect items found."
else
   world.send "drop '%1'"
   world.send "sac '%1'"
end if
</send>
  </trigger>
</triggers>



I have my code in VBscript because it's just what I got comfortable with using for my MUSHclient scripts. The basic logic is probably obvious. When I loot a piece of EQ it fires a different trigger that has me cast "ID" on the loot. The resulting output is what fires this script shown above. It tests to see if a piece of EQ has the best possible spikes and highest possible magic resistance. If it does have both of these attributes it puts the EQ in a container labelled perfect and if the EQ fails to meet this criteria it gets junked. Incidentally, lower class armor may lack magic resistance or spikes entirely, which is why I had those lines set up as optional.
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #7 on Sun 20 Apr 2014 02:32 AM (UTC)
Message
I added \Z to the very end of the regexp.

Without it, it would fire twice, with it, it fired once (on your example above).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #8 on Sun 20 Apr 2014 02:37 AM (UTC)
Message
I think my explanation above was correct. The match that failed for you was 11 lines long, but you were matching on 12 lines. Thus, without the \Z at the end it matched once, and then again when it scrolled up one line.

If you make it match on 15 lines (for example) it matches 5 times (because the 11 lines which cause the match fit into the "subject" 5 times before the first line goes outside the subject range).

Adding in the line "This item is covered with razor sharp spikes" fixed it for you (in a sense) because you now had 12 lines in the subject, and you were matching on 12 lines. Thus it only matched once.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Xavious   (41 posts)  Bio
Date Reply #9 on Sun 20 Apr 2014 03:42 AM (UTC)
Message
Wow.. I just tried it again and it worked this time. I think before I thought I had to put /Z inside the last capture group and not on the outside. I think that just fixed it. Thanks a lot Nick!
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #10 on Sun 20 Apr 2014 04:17 AM (UTC)
Message
Glad it works. This is a more general solution, which hopefully helps others (compared to fiddling around with junk filters).

Quote:

I think before I thought I had to put /Z inside the last capture group


It is \Z not /Z

- Nick Gammon

www.gammon.com.au, www.mushclient.com
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.


27,430 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

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