Page 1 of 2

Newbie Multi-Line Trigger

Posted: Sat Oct 04, 2014 4:58 pm
by Zaphob
I tried around for some time, I read the manual on Trigger chains and filters, but still can't seem to capture anything past the first line.

I have some output like:
Ein Schmetterling ist absolut fit und ist damit absolut, unglaublich
schwaecher als Du. Er kaempft mit seinen Fluegeln. Er macht damit folgenden
Schaden: Schlaege. Damit kaempft er deutlich schlechter als Du. Ein
Schmetterling traegt keine zusaetzliche Ruestung. Damit ist er sehr viel
schlechter als Du geschuetzt.
Ein Schmetterling ist etwa 178cm gross.
Each line comes separately, the line breaks can be anywhere. I would like to put this together in a one line string, then search some regex in there, for example:
  • (ist absolut fit|sieht recht mitgenommen aus|braucht dringend einen Arzt) und ist damit
  • und ist damit (absolut, unglaublich schwaecher|etwa genauso stark|viel staerker) als Du
  • Damit kaempft (er|sie|es) (.*) (als|wie) Du.
  • etc.
The capture would end when the last line ends with " gross.", which it always does.

How can I combine all these lines in a single string, then test accordingly?

I assume, create a new trigger group, match the first regex above. Below the group, add more triggers. One of the triggers should just capture each line, add it to a collective string. Another trigger will end the collection on the word "gross". More triggers can then look at the collective string more specifically for the other regex above.

Any help is greatly appreciated.

Re: Newbie Multi-Line Trigger

Posted: Sat Oct 04, 2014 7:27 pm
by Jor'Mox
So, I'm just going to assume that you already have a trigger that can capture the beginning of this block of text and go from there.

First, you need some sort of indicator that you are starting a new capture. You could test the string to see if it matches your first line trigger, or you could have some sort of test variable that you reset when you reach the end (this seems easier). Then, on the first line, you initialize some global variables to hold the info for you, and use setTriggerStayOpen to extend trigger to capture later lines, though you need to set the fire length for that trigger to at least 1 in the GUI so that you can use that function with it. Then, for each line, you add the new text (from the line variable), and extend how long the trigger stays open to another line, until you reach the end, where you reset your check variable and do whatever you need to do once you have all the info you want.

Here is an example:
Code: [show] | [select all] lua
if not isOpen then   -- this checks for the first line, and initializes your variables
   text = ""
   len = 1
   isOpen = true
end

text = text .. line .. " "   -- this appends each line, with a space added in so that you don't get words running together
len = len + 1   -- this keeps track of how many lines the trigger is capturing

if string.match(line,"gross\.$") then   -- this checks to see if the current line ends with "gross.", and closes things out
   len = 0
   isOpen = false
   -- do other stuff here to actually work with all the text you just captured
end

setTriggerStayOpen("My Trigger Name Here",len)   -- this sets the number of lines for the trigger to capture
Edit: Removed the extra "not" in the last if statement so that the code will work, in case someone else wants to use it.

Re: Newbie Multi-Line Trigger

Posted: Sat Oct 04, 2014 11:14 pm
by Zaphob
Thanks Jor'Mox, this was very helpful indeed.

So here is what I did:
  • create a new trigger, which would be triggered by the first line of the text block to be captured.
  • set "fire length" to 1 in trigger GUI
  • put your code in the trigger
There was only one problem, I had to remove your "not" from the line which checks the match with "gross."
Now it works like a charm. I will continue to test this more and look into things like setTriggerStayOpen() now. Thanks again!

Re: Newbie Multi-Line Trigger

Posted: Sun Oct 05, 2014 12:20 am
by Jor'Mox
Heh. Downside of writing something in a text box... it is easy to make simple mistakes, particularly in logic, that would be impossible to make if I had actually tested it. I'm glad it worked for you. :)

Re: Newbie Multi-Line Trigger

Posted: Thu Oct 09, 2014 11:07 pm
by Zaphob
Jor'Mox wrote:you reach the end, where you reset your check variable and do whatever you need to do once you have all the info you want.
I solved some simpler patterns, but still struggle with the more complex regex. Here is another example:
(Er|Sie|Es) ist gegen (schneidenden Schaden|stechenden Schaden|reissenden Schaden) (sehr anfaellig|
geschuetzt|extrem gut geschuetzt)
How would I use the Mudlet "perl regex" trigger engine to match these patterns from the combined multi-line text?

Sure I can build my way around this and produce some more lua logic to translate above regex to basic lua string.match(), etc. - but maybe I can use the Mudlet perl regex triggers, as well?

(By the way, these examples I took from a script written for the TinyFugue client. Maybe there is a recommended way to import Tiny Fugue scripts and configuration to Mudlet?)

Re: Newbie Multi-Line Trigger

Posted: Thu Oct 09, 2014 11:20 pm
by Jor'Mox
Well, given that the text can be broken into different lines arbitrarily, you can't really use the Mudlet trigger engine to do the pattern matching. So you need to use string.match function calls using the entire, collected text as the string to search, as it will then have been put all into one line, letting you do the necessary pattern matching.

Granted, the fact that I don't understand the language being used makes it difficult to really assess things, not that the actual text should really matter. But, unless you know where line breaks will be, you really can't use triggers to handle things, so you will have to use string.match. If you DO know where line breaks will fall, even if you don't know the order, then it is different, and you can use normal triggers and appropriate patterns to gather the information. In and of themselves, patterns like what you have should work just fine in the Mudlet trigger engine as regex triggers.

Re: Newbie Multi-Line Trigger

Posted: Mon Oct 20, 2014 9:59 pm
by Zaphob
Unfortunately, the line breaks are completely random aka when the line is full. Depending on length of names, etc, this can be at different places. So I will go the string.match way and see where it takes me.

Then again, pattern matching doesn't offer the exact functionality I try to recreate, some examples were listed above. So I need to rethink the logic, sometimes writing many lines where regex only needed 1. I will try to do so, unless I find a way to use the Mudlet trigger engine again.

I stumbled across this weird behavior.

I was under the impression, a pattern like (.-) would match the least possible number of characters, whereas (.*) would match the most greedy. If so, this does not make sense:
Code: [show] | [select all] lua
text = "Eine Biene ist absolut fit und ist damit unglaublich schwaecher als Du. Sie hat einen Bienenstachel gezueckt. Ein Bienenstachel macht folgenden Schaden: Stiche. Damit kaempft sie sehr viel schlechter als Du. Eine Biene traegt keine zusaetzliche Ruestung. Damit ist sie sehr viel schlechter als Du geschuetzt.  Eine Biene ist etwa 2cm gross."
weapon, damagetype = string.match(text, "%. (.-) macht folgenden Schaden: ([^%.]-)%.")
I would assume, damagetype would yield "Stiche" and weapon would yield "Ein Bienenstachel". Right? Well, wrong:
Code: [show] | [select all] lua
display(weapon)
"Sie hat einen Bienenstachel gezueckt. Ein Bienenstachel"
Why is that so greedy?

Re: Newbie Multi-Line Trigger

Posted: Wed Oct 22, 2014 11:35 am
by Zaphob
Still not sure, why it was so greedy, but the following more specific pattern works as expected:
Code: [show] | [select all] lua
weapon, damagetype = string.match(text, "%. ([^%.]-) macht folgenden Schaden: ([^%.]-)%.")
display(weapon)
"Ein Bienenstachel"

Re: Newbie Multi-Line Trigger

Posted: Wed Oct 22, 2014 2:14 pm
by Jor'Mox
Using .- will only be different from .* when it is followed immediately by some other pattern that is variable in size. It will yield characters to let the other pattern have them, so that the following pattern will get as big a match as possible, as opposed to forcing it to have the smallest match possible.

So, for example, suppose your pattern was this: (.*)([s]+), and you were matching it against: The snake said 'hiss'.
matches[2] would be "The snake said 'his", and matches[3] would be "s".

If instead you used (.-)([s]+), your matches would be "The snake said 'hi" and "ss" respectively.

Hopefully that makes sense.

Re: Newbie Multi-Line Trigger

Posted: Wed Oct 22, 2014 3:16 pm
by Zaphob
Thanks Jor'Mox. Here is yet another explanation I received:
because matching only goes in one direction (from left to right), you need to distinguish match start and match end, and you can only control greedyness of the end
the start is always as early (greedy) as possible
I am getting a better feeling for this .. slowly :D