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") < 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,120 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,330 views.
It is now over 60 days since the last post. This thread is closed.
Refresh page
top