Capturing same thing more than once in a single line.

Posted by Somegirl on Wed 24 Nov 2004 04:39 PM — 24 posts, 83,990 views.

#0
Here's what the output looks like:

Blah, Blah, Blah, Blah, Blah, Blah,

The end of the line can contain the last "Blah" in the following ways:
Blah
Blah,
Blah, <--one space

I want to capture and send to a list each "Blah" which are names that are always capitalized. I've tried triggering several combinations with ([A-Z][a-z]+) in it to match and capture the names. But then when I do world.Note "%1" to test and see if it gets them all, it doesn't seem to.

Currently I'm making do with a trigger that captures everything and a subroutine that split()'s it. I have had other instances where I would like to capture multiple items of the same type on a single line. So not only would I like to stop using a .* trigger and make it cleaner, but I've had other instances where I can't figure out how to do something like this.

I think this is also similar to colouring individual words in a line, which I would also like to be able to do.

Any ideas? Sorry if I'm missing something obvious here.
USA #1
You can color individual words, just use a regexp, and match just that word.

You should be able to catch the names, want to post some examples?

However, if the same trigger matches multiple times on a line, then it will only get sent to script once (You can have that trigger match, and then get the whole line and split it up though).
#2
Yeah, that's what I do already. I send the whole line to script and split it up there. I was just hoping for something cleaner that could do it in the trigger itself. I'm not sure if I'm making myself clear here.

I get a block of names between prompts like I posted. It's multiple lines with several names in each line. A line can end with a comma, a comma and a single space, or nothing (i.e. just the name). I want to capture all the names in each line individually and append them to a list in Python.

As for coloring individual names, I can't figure out how to do that without coloring the whole line. I've looked through the forums, but the solutions presented seemed to indicate that I needed to replace the entire line with one that colors the one word or name. So I am probably missing something simple.

btw: I never use anything but a RegExp if I can help it.

Edit: okay I figured out how to do one-word coloring. Now my question becomes:
How do I color multiple different items in the same line like the the QWHO list in IRE games. Do I need to make a trigger for each name? Can I (hopefully) squeeze them all into a single trigger? I haven't tried yet as I was in a hurry to edit. I will come back after I look into it.
Amended on Thu 25 Nov 2004 09:43 AM by Somegirl
#3
Quote:
<triggers>
  <trigger
   custom_colour="17"
   enabled="y"
   expand_variables="y"
   group="colors"
   ignore_case="y"
   keep_evaluating="y"
   match="(@!friends)"
   regexp="y"
   sequence="100"
   other_text_colour="royalblue"
   other_back_colour="white"
  >
  </trigger>
</triggers>


<variables>
  <variable name="friends">somegirl|gore|nick|flannel|shadowfyr|</variable>
</variables>


etc, this'll color those names when they are seen in the qw list or anywhere

(note, I didn't write this script! there was a post about this before)

Is this what you needed?
#4
sorry, I didn't come up with the idea of these "triggers" not script heh, also you can modify it so that you have an alias like, fr person, to add name| to your variable, or remove, or ally/unally, or whatever etc etc
#5
Hrm, actually I just tested this.. and it won't color say, Nick if Nick is on the same line twice. Any ideas?
#6
Ok sorry, I answer'd my own question, heh. The trigger should be as follows:

Quote:
<triggers>
  <trigger
   custom_colour="17"
   enabled="y"
   expand_variables="y"
   group="colors"
   ignore_case="y"
   keep_evaluating="y"
   match="(@!friends)"
   regexp="y"
   repeat="y"
   sequence="100"
   other_text_colour="royalblue"
   other_back_colour="white"
  >
  </trigger>
</triggers>


Note, repeat on same line has been checked, where it wasn't before.
#7
Yup, 'repeat on same line' makes it work. Now why won't it work to capture like I intend?
Australia Forum Administrator #8
Trigger scripts are only executed once per line, not once per match.

However there are ways of processing the capture multiple times.

For a start, under Lua you have a "gmatch" function that applies a regular expression to a string, and then calls a function that you supply for every match. Here is an example:


t = rex.new ("(a|b|c)")

function f (m, t)
  Note ("Matched: " .. m)
end -- function

t:gmatch ("cat mat bat catch", f)

-- output:

Matched: c
Matched: a
Matched: a
Matched: b
Matched: a
Matched: c
Matched: a
Matched: c


So, what you can do in your trigger script (given that it is only called once) is get the regular expression, and then apply it to the matching line as shown above.

Remember, to get the trigger match string (what it matches on), just do this:

s = GetTriggerInfo ("triggername", 1)
#9
Huh?

Nooo! Don't make me learn another language!
You're really hot on this Lua thing aren't you? Maybe I can find something in Python eventually. But right now, I'll just script it like I have been by delineating. Thanks anyhow. That answers my question.
USA #10
Basically He's just splitting.

You only get the script called once per line, not once per match (if it matches multiple times on a line), so you have to work around that.

And yeah, he seems to have discovered Lua, and gone crazy.
Although, it does solve many things that we couldnt do before (callbacks, and better usage of other windows).

Nick, any chance Lua might be able to insert things on lines, so we dont have to omit/note? Or clean my room?
Australia Forum Administrator #11
Quote:

I'll just script it like I have been by delineating


With any language you can take the entire line and reprocess it to find the submatches. My example in Lua just showed the idea.

Quote:

And yeah, he seems to have discovered Lua, and gone crazy.


Indeed. ;)

Quote:

Nick, any chance Lua might be able to insert things on lines, so we dont have to omit/note?


You still have the fundamental design problems with doing that - things like that fact that lines arrive in pieces (packets) not necessarily terminated by a newline. When do you start matching? At the end of a packet? Say you want to replace "kobold" with "monster" and you get:

packet 1: kobo
packet 2: ld

When does the "find and replace" get triggered off? And what of ANSI codes? MXP codes? MXP entities?

Quote:

Or clean my room


How dirty is it?
#12
Wouldn't
(.*?)
and checking the omit from log/output take care of stuff in your room? Of course, it might have adverse effects on things you don't want omitted. (girlfriends, pets, etc...)
Greece #13
Quote:

When does the "find and replace" get triggered off? And what of ANSI codes? MXP codes? MXP entities?

Well, it would get triggered off the newline, since you don't really need to match it as it comes, only when it's done, and about colour codes, it's a compromise, as it's better than nothing, for example:
Say I want to replace "blue bear" with "red horse"
<green>You see a <blue>blue<green> bear.
The output would be
<green>You see a <blue>red horse.

Ideally, we would be able to add raw ANSI codes to the string to be replaced, but still, not many lines I want to replace have more than one color.
About the color thing, think you could change it to match on raw colors? Like, add an option, which for example would have triggers of this style:
<green>*gets damaged! <blue>It scraps!

Essentially triggers would not omit the colour codes, but would instead keep them as normal text we could match on, so we could do:
\1B[31m*some red text.
Would match on "\1B[31mSome red text".

Wouldn't that be as easy to implement as just keeping the colour codes in the line and adding an option? It would allow us to match colors that change mid-line, although, as I said, those are not very frequent.
Australia Forum Administrator #14
OK, say you have at least two packets to make up a line, not something that is particularly unusual.

Now when the first one arrives, MUSHclient has to display it, in case there is no second packet.

eg.


Welcome to Blah MUD!
Enter your name ...


Now if I wait for the newline, you don't get to see "Enter your name ...". If I don't then the text is already on the screen, it is a bit late to start doing find-and-replace on it.
USA #15
The replace thing wasnt in any seriousness, I know the design problems (especially considering it wouldnt get to Lua until after it matched, which means after it was displayed, which well, yeah, weve been over this).

As for color, I'd just as soon have it be ANSI sequences. And MXP, and everything.
If someone is going to be screwing around with low level stuff, they should be able to take care of colors/MXP/whatever.
Just like in assembly, or C, or whatever, as opposed to something higher (VBscript), yes, you MIGHT have overflows, or whatever, but since youre coding at a lower level, thats to be expected, and youre expected to be able to take care of that.

As for the line triggering problem, its the same thing if youre omitting. Yes, you might be inserting something, or changing something, but we do the same thing with things being omitted.

And make it a plugin callback, I think that would be the most useful. Because you'd shield 'normal' users from it, and wouldnt have to rewrite anything that already exists. Just give the plugin the line, and have it return the new line (both including color/mxp/etc, just an assembly of packets, let the plugin writer deal with everything, to give him the most flexibility).
Greece #16
Quote:

Now if I wait for the newline, you don't get to see "Enter your name ...". If I don't then the text is already on the screen, it is a bit late to start doing find-and-replace on it.

What happens if the user wants to omit "Enter your name*" from output? Doesn't this still happen?
Australia Forum Administrator #17
Yes, when the newline eventually appears, *after* they have entered their name.
Greece #18
So the problem exists already, it's not exclusive to the replacement function.
USA #19
Which is why I dont see it at a major problem. Yes, its going to sometimes be an awkward transition, for slow connections or prompts, or a few other situations. But we do the same with omitting.
Yes, it doesnt work quite like we'd like it to, but we cant control the servers, and it isnt a crippling problem.
Australia Forum Administrator #20
Yes, the problem already exists, but what you are asking is for something to be retrospectively changed on the screen. At present all the "problem" is, is that trigger don't fire until a newline.

Australia Forum Administrator #21
Well, I think I have worked out a way of solving the "replace stuff in lines" problem. The major problem so far has been that in trigger matching, if you try to do fancy omitting from output in "send to script" any world.notes are also omitted, and if you wait until a trigger script (in the script file) executes, the original line has already been omitted.

I was reluctant to alter the way trigger calls worked, because that would break existing scripts. However with Lua, there is a way *grin*.

Lua allows optional arguments, so I have added a fourth argument to the trigger script (only available under Lua). This fourth argument is a table of all the style runs in the matching line, including the text colour, background colour, text itself, and the style type (eg. bold).

Now with a simple bit of scripting, you can replace one word with another. Here is an example:


function my_trigger (name, line, wildcards, styles)

  for _, v in pairs (styles) do
    
    ColourNote (RGBColourToName (v.textcolour), 
                RGBColourToName (v.backcolour), 
                (string.gsub (v.text, "will", "*WILL*")))  
  end

end



I think this is pretty self-explanatory. It echoes the existing line to the output window with ColourNote (translating colour numbers to colour names). This keeps existing colours. Then by doing a gsub (global substitution) it replaces the word "will" by "*WILL*".

Now of course, if "will" spans a colour boundary, then it won't match, but that sort of problem is the thing that was always going to be a problem with trying to replace words in coloured text. The next post will show how it looks:
Amended on Sat 27 Nov 2004 02:42 AM by Nick Gammon
Australia Forum Administrator #22

Hell
As if picked up by the scruff of your neck by a mighty hand, you find
yourself unceremoniously dumped at a strange gateway.  Here is the
place which *WILL* determine your fate.  Whether you *WILL* be sent back
to life as you once knew it, or proceed onto a far yet bleaker pathway.
The time has come for you to plead your case and await judgement for the
crimes that have been placed upon your head.  Speak wisely and choose
your words carefully, for your testimony *WILL* be written in the ledgers
of the Gods, and *WILL* determine the path you *WILL* ultimately travel.
Exits: none.
A mystical spring flows majestically from a glowing circle of blue.
A fountain of fresh blood flows in the corner.
A demon imp hovers nearby...drooling constantly with a fiendish grin.

<1000hp 100m 110mv> 
think I will go to sleep
You think 'I *WILL* go to sleep'

<1000hp 100m 110mv> 
<1000hp 100m 110mv> 
Australia Forum Administrator #23
In the example above, I had a simple trigger that matched the word "will" (regular expression), omitted from output (so you didn't get two of them), and called the script shown above.

Notice how the colour of the original line is retained.