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.
 Entire forum ➜ MUSHclient ➜ General ➜ Matching a trigger multiple times on the same line

Matching a trigger multiple times on the same line

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


Posted by Mudguy   (4 posts)  Bio
Date Mon 19 Feb 2007 03:32 PM (UTC)

Amended on Mon 19 Feb 2007 03:34 PM (UTC) by Mudguy

Message
I have a trigger that looks like this:

<triggers>
  <trigger
   enabled="y"
   expand_variables="y"
   keep_evaluating="y"
   match="[ *(\d+)] (ginseng root|valerian|goldenseal root|myrrh gum)"
   regexp="y"
   repeat="y"
   send_to="12"
   sequence="100"
  >
  <send>do_stuff()</send>
  </trigger>
</triggers>

and I am wanting it to match exactly four times on this text from the server:

  [  11] bayberry bark      [   7] bellwort flower    [  10] black cohosh
  [  80] bloodroot leaf     [   8] blueberry          [  39] echinacea
  [  15] ginseng root       [  16] goldenseal root    [   8] hawthorn berry
  [  14] irid moss          [  18] kelp               [  14] kola nut
  [ 200] kuzu root          [ 498] lady's slipper     [  10] leather
  [  30] lobelia seed       [  16] myrrh gum          [   3] piece of stag's
  [ 101] prickly ash bark   [  11] prickly pear       [  11] sileris
  [  11] skullcap           [  10] slippery elm       [ 237] valerian
  [  54] venom sac          [   2] yellow ink

However, it doesn't work like I want it to on line 3 of the input - it matches on the ginseng entry, but not on the goldenseal entry. This is something of a showstopper.

What is the problem here, and how do I fix it? I have ticked the 'Repeat on same line' box in the trigger creation dialogue box, and as far as I can see, the trigger's not greedy enough to eat the whole line.
Top

Posted by Rakon   USA  (123 posts)  Bio
Date Reply #1 on Mon 19 Feb 2007 06:46 PM (UTC)
Message
My trigger for that looked like this, and it worked all the time for capture:

<triggers>
  <trigger
   enabled="y"
   expand_variables="y"
   ignore_case="y"
   keep_evaluating="y"
   match="[(?:\s+)(\d+)](?:\s+)(.*?)(?:\s+)"
   regexp="y"
   repeat="y"
   send_to="12"
   sequence="100"
  >
  <send>if "%2" in world.GetVariable("herblist"):
 if int("%1") &lt; 100:
  al_alert(string.capitalize("%2") + "  left!")</send>
  </trigger>
</triggers>

And in the variable for 'herblist' was just what herbs I wanted to keep track of:

<variables>
  <variable name="herblist">bayberry bark|bellwort flower|echinacea|irid moss|prickly ash bark|skullcap|valerian|ginseng root|hawthorn berry|kelp|lobelia seed|prickly pear|sileris|slippery elm|cohosh|goldenseal root|kola nut</variable>
</variables>


Hope that helps.

Yes, I am a criminal.
My crime is that of curiosity.
My crime is that of judging people by what they say and think, not what they look like.
My crime is that of outsmarting you, something that you will never forgive me for.
Top

Posted by Shadowfyr   USA  (1,788 posts)  Bio
Date Reply #2 on Mon 19 Feb 2007 07:18 PM (UTC)
Message
Well.. My guess is that its the spaces. I.e., its actually seeing:

Find:
ginseng +
root|valerian|goldenseal +
root|myrrh gum

This is why Rakon's works and yours doesn't. His is looking for the name "after" the lines are already captured. The solution is to use:

((ginseng root)|valerian|(goldenseal root)|(myrrh gum))

I think. This will wreck havoc with your wildcard count, but it should specifically "require" that each phrase be treated as a complete match, and not as three seperate sets of options.

Frankly, the wildcard issue always bugged me... Some triggers can get unbelievably complex due to this and until recently there was no way to "get" the wildcards over a certain number, so you have to compromise. Now.. You are *still* stuck trying to figure out "which" wildcard is the right one, because () also designates a wildcard, not just a grouping. In a long complex pattern with "many" optionals, you might have 5 actual wildcards, but 50 "subgroups" and the wildcard locations needed to return the "intended" stuff might be 4, 15, 25, 43 and 48, of which "4" would have previously been the only one you could get to. Rakon's solution works better, but has the flaw that if someone uses the same identical indention and layout for say, a shop, the script is going to waste time parsing things it doesn't need to, looking for something in the shop that isn't there. You can simply use an alias that enables the trigger when needed, then disables it when something else happens, but its not always possible to figure out what that "something else" is.

Your kind of stuck either doing it so it can't match, then fiddling with the wildcards to get what you intended in the first place, letting the trigger match things it isn't supposed to, or creating some set of rules to enable/disable the trigger. All three methods have annoyances.
Top

Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Reply #3 on Mon 19 Feb 2007 07:35 PM (UTC)

Amended on Mon 19 Feb 2007 07:42 PM (UTC) by Nick Gammon

Message
Quote:

... it matches on the ginseng entry, but not on the goldenseal entry ...


The real problem here is that the trigger processing optimizes certain things. In particular, "repeat on same line" is intended for colouring multiple words. If you set a "change colour", like this you will see it:


custom_colour="2"


You can see from that, that it does indeed match twice when expected.

However, and this is what is catching your script, it then calls the script once, per line. Thus the script is called for the first match only.

The good news is that there is a fairly simple way around this.

To do this you will need a script file (not just "send to script"), which I am guessing you have from the way you call do_stuff ().

Next you need to change your trigger slightly to call a script function by name, rather than the way you did, like this:


<triggers>
  <trigger
   enabled="y"
   expand_variables="y"
   keep_evaluating="y"
   match="\[ *(\d+)\] (ginseng root|valerian|goldenseal root|myrrh gum)"
   name="herb_trigger"
   regexp="y"
   repeat="y"
   script="herb_trigger_script"
   sequence="100"
  >
  </trigger>
</triggers>



I also gave it a name, for reasons that will become apparent (the name "herb_trigger").

Now inside the script file we need to reprocess that line, using the PCRE regexp handler, built into the Lua script. This is an exact copy of the one that MUSHclient uses, and thus we can pass to it the same regular expression from the trigger.

To allow for future enhancement, I pull the regexp directly from the trigger itself.

Here is the script:


function herb_trigger_script (name, line, wildcards)
 
  -- function to handle individual matches
  local function one_herb (m, t)
    print ("count", t [1])
    print ("herb",  t [2])
  end -- one_herb 

  local re = rex.new (GetTriggerInfo (name, 1))  -- get the match text, make into a regexp
  re:gmatch (line, one_herb)  -- match repeatedly, call function

end -- herb_trigger_script 


What this does is use re:gmatch to re-match on the trigger line, calling the function one_herb for each match. Then you can do whatever you want with the match. The function one_herb is passed a table of substrings (t), out of which I extract the count and herb name.

You could optimize this slightly by moving the call to rex.new out of the function, and simply pass the name of the trigger to it, to save compiling the regular expression every time, but it might not make much difference.

My output was:


  [  11] bayberry bark      [   7] bellwort flower    [  10] black cohosh
  [  80] bloodroot leaf     [   8] blueberry          [  39] echinacea
  [  15] ginseng root       [  16] goldenseal root    [   8] hawthorn berry
count 15
herb ginseng root
count 16
herb goldenseal root
  [  14] irid moss          [  18] kelp               [  14] kola nut
  [ 200] kuzu root          [ 498] lady's slipper     [  10] leather
  [  30] lobelia seed       [  16] myrrh gum          [   3] piece of stag's
count 16
herb myrrh gum
  [ 101] prickly ash bark   [  11] prickly pear       [  11] sileris
  [  11] skullcap           [  10] slippery elm       [ 237] valerian
count 237
herb valerian
  [  54] venom sac          [   2] yellow ink


Quote:

Some triggers can get unbelievably complex due to this and until recently there was no way to "get" the wildcards over a certain number, so you have to compromise.


My solution above shows how you can achieve this without too much complexity.

- 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.


20,358 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.