reg ex for prompt?

Posted by Chaosmstr on Tue 21 Jul 2015 12:16 AM — 16 posts, 62,939 views.

#0
I feel dumb.

I've been messing with this for days, time to ask the experts.

I'm trying to use the "prompt newline" plugin referenced in the FAQ point 11. I'm trying to convert my prompt to a reg ex. I'm staring at the regex table, and what I think should work just... doesn't.


Prompt is:

<733hp(733) 522ma(522) 569mv(29188) s: ok 126636gp >


I've tried changing the numbers to \d+, I've tried \<*\>, nothing seems to work.

I'm assuming that the plugin isn't broken anymore and it's just me not getting the regex correct.

Programming... my nemesis.Ugh.




TRACE msgs show:
Executing Plugin Add_Newline_To_Prompt_2 script "OnPluginPacketReceived"

Packet debug shows:

Incoming packet: 11 (224 bytes) at Monday, July 20, 2015, 1:37:36 PM



...[01m<.[00m.[1   0a 0d 1b 5b 30 31 6d 3c 1b 5b 30 30 6d 1b 5b 31
m.[31m733.[00m.[   6d 1b 5b 33 31 6d 37 33 33 1b 5b 30 30 6d 1b 5b
31mhp.[00m(.[31m   33 31 6d 68 70 1b 5b 30 30 6d 28 1b 5b 33 31 6d
733.[00m) .[1m.[   37 33 33 1b 5b 30 30 6d 29 20 1b 5b 31 6d 1b 5b
34m522.[00m.[34m   33 34 6d 35 32 32 1b 5b 30 30 6d 1b 5b 33 34 6d
ma.[00m(.[34m522   6d 61 1b 5b 30 30 6d 28 1b 5b 33 34 6d 35 32 32
.[00m) .[1m.[32m   1b 5b 30 30 6d 29 20 1b 5b 31 6d 1b 5b 33 32 6d
569.[00m.[32mmv.   35 36 39 1b 5b 30 30 6d 1b 5b 33 32 6d 6d 76 1b
[00m(.[36m29188.   5b 30 30 6d 28 1b 5b 33 36 6d 32 39 31 38 38 1b
[00m) s: .[1m.[0   5b 30 30 6d 29 20 73 3a 20 1b 5b 31 6d 1b 5b 30
1mok.[00m .[1m.[   31 6d 6f 6b 1b 5b 30 30 6d 20 1b 5b 31 6d 1b 5b
35m126636.[00m.[   33 35 6d 31 32 36 36 33 36 1b 5b 30 30 6d 1b 5b
35mgp.[00m .[1m.   33 35 6d 67 70 1b 5b 30 30 6d 20 1b 5b 31 6d 1b
[01m>.[00m .[00m   5b 30 31 6d 3e 1b 5b 30 30 6d 20 1b 5b 30 30 6d
[\code]
Australia Forum Administrator #1
Could you show what you tried please?
#2
So far I've tried:

^\<(.*?)\>$
^\<\d+hp\(.*?)\>?
^\<\d.+hp\(\d+\)\s\d+ma\(\d+\)\s\d+mv\(\d+\).+\>$

Which all work for trigger testing offline, but do nothing when I get online.

I've also seen that the "add_newline_to_prompt_2" plugin get stuck in a loop sending "ff fd 01" (from the packet debug screen) and trace showing Executing Plugin Add_Newline_To_Prompt_2 script "OnPluginPacketReceived" repeatedly... but only if I log in, log off, log back in again without closing the world down.

The first time I run the world file, it does not get stuck in a loop. It does not give a newline, and the prompt line trigger does not fire.
#3
Oh, and when it gets stuck in the loop, every 3/5 sends gets a receive packet back from the MUD.

ff fc 01 ff fb 01
Australia Forum Administrator #4
Can you post the whole plugin? What you had was a PCRE regular expression, not a Lua one. Also on the raw packet you need to allow for the ANSI colour sequences. They are in the packet, thus you must test for them.
#5
It's your code from a previous post found from point 11 on the FAQ.

I used the reg ex from the trigger... typed in <*> and hit convert. Edited from there using the key from the Reg Ex matching page.



<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient[
  <!ENTITY prompt_regexp "^\<\d.+hp\(\d+\)\s\d+ma\(\d+\)\s\d+mv\(\d+\).+\>$" > 
]>
<!-- MuClient version 3.59 -->

<!-- Plugin "Add_Newline_To_Prompt_2" generated by Plugin Wizard -->

<muclient>
<plugin
   name="Add_Newline_To_Prompt_2"
   author="Nick Gammon"
   id="a14e9768c3ad5ce50d202ee0"
   language="Lua"
   purpose="Adds a newline to prompt lines"
   date_written="2004-12-13 14:27"
   requires="3.59"
   version="1.0"
   >
<description trim="y">
Detects prompt lines without a newline, and if found, adds one.

Change ENTITY line on 3rd line of plugin to be a regular expression 
that matches your prompt.

</description>

</plugin>

<!--  Script  -->

<script>

re = rex.new ("&prompt_regexp;")

<![CDATA[

function OnPluginPacketReceived (s)

  if (re:match (s)) then
    return s .. "\n"	
  else
    return s
  end -- if 
  
end -- function OnPluginPacketReceived
]]>
</script>

</muclient>
Amended on Wed 22 Jul 2015 03:39 AM by Chaosmstr
#6
How do I test for the colors, and what is the proper LUA reg expression please?
Australia Forum Administrator #7
Actually, since the plugin does re.new that is a PCRE regular expression, not a Lua one.

As for the colours, you just have to match them. For example:


.[01m


The dot will be an escape, so that is:



ESC [ 01m


So in PCRE that would be:


\e\[01m


Since it is inside quotes you would have to double the backslashes:


\\e\\[01m


Now instead of testing for "01" you could test for any digits:



\\e\\[[0-9]+m


Now in every place in the prompt regexp that there is a colour code you would put that. :(

I took your example, and wrote a small Lua script to work out how many there are:


message = "\n\r\027[01m<\027[00m\027[1m\027[31m733\027[00m\027[31mhp\027[00m(\027[31m733\027[00m) " ..
"\027[1m\027[34m522\027[00m\027[34mma\027[00m(\027[34m522\027[00m) " ..
"\027[1m\027[32m569\027[00m\027[32mmv\027[00m(\027[36m29188\027[00m) " ..
"s: \027[1m\027[01mok\027[00m \027[1m\027[35m126636\027[00m\027[35mgp\027[00m " ..
"\027[1m\027[01m>\027[00m \027[00m"


message = string.gsub (message, "\027%[%d+m", "[COLOURCODE]")

print (message)


Results:


[COLOURCODE]<[COLOURCODE][COLOURCODE][COLOURCODE]733[COLOURCODE][COLOURCODE]hp[COLOURCODE]
([COLOURCODE]733[COLOURCODE])
[COLOURCODE][COLOURCODE]522[COLOURCODE][COLOURCODE]ma[COLOURCODE]([COLOURCODE]522[COLOURCODE])
[COLOURCODE][COLOURCODE]569[COLOURCODE][COLOURCODE]mv[COLOURCODE]([COLOURCODE]29188[COLOURCODE]) s:
[COLOURCODE][COLOURCODE]ok[COLOURCODE] [COLOURCODE][COLOURCODE]126636[COLOURCODE][COLOURCODE]gp[COLOURCODE]
[COLOURCODE][COLOURCODE]>[COLOURCODE] [COLOURCODE]


Which is pretty funny. I'll see if I can come up with a regexp for you. This looks pretty tedious.

Stripping out the colour codes, I get:


<733hp(733) 522ma(522) 569mv(29188) s: ok 126636gp > 
Amended on Fri 24 Jul 2015 11:37 PM by Nick Gammon
Australia Forum Administrator #8
This was such a complex prompt I decided to go for an LPEG parser. :)

Template:saveplugin=Add_NewLine_To_Prompt_LPEG
To save and install the Add_NewLine_To_Prompt_LPEG plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Add_NewLine_To_Prompt_LPEG.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Add_NewLine_To_Prompt_LPEG.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.



<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE muclient>

<muclient>
<plugin
   name="Add_NewLine_To_Prompt_LPEG"
   author="Nick Gammon"
   id="fb4b4d91ab9f3eae363768a8"
   language="Lua"
   purpose="Forces a newline after a prompt line"
   date_written="2015-07-25"
   requires="4.67"
   version="1.0"
   >
</plugin>


<script>
<![CDATA[

local P = lpeg.P  -- literal string
local R = lpeg.R  -- range
local C = lpeg.C  -- capture

crlf = (P"\n" +  P"\r")^1  -- cr/lf or lf/cr etc.
digits = R ("09")^1        -- 0 to 9
space = P" "               -- a space
colour = (P ("\027[") * digits * P"m" * space^0)^0  -- ESC [ digits m + optional spaces
number_in_brackets = P"(" * colour * digits * colour * P")" * space^1

-- Visibly, the line looks like this: <733hp(733) 522ma(522) 569mv(29188) s: ok 126636gp >
-- The MUD intersperses ANSI colour codes liberally through the prompt
-- We look for zero or more of them in various places 

line = crlf
       * colour * P"<"                              -- opening < symbol
       * colour * digits * colour * P"hp" * colour  -- 733hp
       * number_in_brackets                         -- (733)
       * colour * digits * colour * P"ma" * colour  -- 522ma
       * number_in_brackets                         -- (522)
       * colour * digits * colour * P"mv" * colour  -- 569mv
       * number_in_brackets                         -- (569)
       * P"s:" * space^1 * colour * (R("az") + R("AZ"))^1 * colour   -- s: ok
       * digits * colour * P"gp" * colour           -- 126636gp
       * P">" * colour                              -- closing > symbol
       
function OnPluginPacketReceived (s)
  matched = lpeg.match (line, s)
  if matched then
    return s:sub (1, matched - 1) .. "\n" .. s:sub (matched)  
  end -- if

  -- no match, return packet  
  return s
end -- function OnPluginPacketReceived
]]>
</script>

</muclient>


This uses LPEG - a sophisticated parsing grammer built into MUSHclient.

It made it reasonably easy to express the complexity of the prompt line without too many obscure symbols.

The big expression above is "line" which is broken up into its component parts (of the prompt).

In LPEG things like lpeg.P"<" match that literal string. Then the "*" symbols concatenates. So the prompt line is built up by concatenating the fixed things (like "mv") with variable things (like digits), and optional colour codes.

It worked on the test packet you gave me.




To expand on this line:


colour = (P ("\027[") * digits * P"m" * space^0)^0  -- ESC [ digits m + optional spaces


  • P ("\027[") --> literally ESC followed by [
  • digits --> one or more digits as defined earlier
  • P"m" --> the letter "m"
  • space^0 --> zero or more spaces
  • The whole thing is in brackets with ^0 after it, which means 0 or more of the whole thing. That handles the cases where we had two or more ANSI colour sequences in a row.
  • The asterisk means concatenation (this after that)


The "+" symbol used in a couple of places means "or" (that is, this or that).




Time taken

The parser might look complex but it runs fast enough. On non-matching lines, my tests show that it takes about 24 µs to match, on matching lines (prompts) it takes about 200 µs to match (longer, presumably, because a failure bails out quickly).

So for most lines the overhead is very small (there are 1000000 µs to a second), and for prompts it is still 1/5 of a millisecond, and in any event, you often wait for player input after a prompt.
Amended on Sat 25 Jul 2015 06:39 AM by Nick Gammon
Australia Forum Administrator #9
Just for interest, I reworked the plugin to use the LPEG "re" module. This lets you express a pattern in a more "regular expression" way:

Template:saveplugin=Add_NewLine_To_Prompt_LPEG_re
To save and install the Add_NewLine_To_Prompt_LPEG_re plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Add_NewLine_To_Prompt_LPEG_re.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Add_NewLine_To_Prompt_LPEG_re.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.



<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE muclient>

<muclient>
<plugin
   name="Add_NewLine_To_Prompt_LPEG_re"
   author="Nick Gammon"
   id="af8df9687a2f1b01abb7d750"
   language="Lua"
   purpose="Forces a newline after a prompt line"
   date_written="2015-07-26"
   requires="4.67"
   version="1.0"
   >
</plugin>

<script>
<![CDATA[

require "re"

prompt = re.compile([[
  prompt <- crlf colour '<'                   -- start of prompt
            colour %d+ colour 'hp' colour     -- 733hp
            numberInBrackets                  -- (733)
            colour %d+ colour 'ma' colour     -- 522ma
            numberInBrackets                  -- (522)
            colour %d+ colour 'mv' colour     -- 569mv
            numberInBrackets                  -- (569)
            's:' %s+ colour %a+ colour        -- s: ok
            %d+ colour 'gp'                   -- 126636gp
            colour '>' colour                 -- closing > symbol

   numberInBrackets <- '(' colour %d+ colour ')' %s+

]] .. 

   -- escape codes like \027 \n \r do not work inside long strings

   "colour  <- ('\027' '[' %d+ 'm' %s*)* " ..  -- colour code: ESC [ 42 m
   "crlf    <- ('\n' / '\r')+"                 -- carriage return/line feed(s)
   )

       
function OnPluginPacketReceived (s)
  matched = prompt:match (s)
  if matched then
    return s:sub (1, matched - 1) .. "\n" .. s:sub (matched)  
  end -- if

  -- no match, return packet  
  return s
end -- function OnPluginPacketReceived
]]>
</script>

</muclient>


This should work the same as the other one, but is a bit more self-documenting, in case you want to change it for some other prompt.
#10
Maybe I'm not understanding how this is used.
It's to add a linefeed to the end of a prompt line so that you can trigger on the prompt line, but if I have this complicated prompt line, maybe I'm not even setting up my trigger correctly.

How can I tell if this works?

There is no added line feed to the screen.
I added a line to the code to see if it would do anything.. and it doesn't seem to.



function OnPluginPacketReceived (s)
  matched = prompt:match (s)
  if matched then
    return s:sub (1, matched - 1) .. "\n" .. s:sub (matched)  
    print ("seen")
  end -- if

  -- no match, return packet  
  return s
Amended on Mon 27 Jul 2015 10:12 PM by Chaosmstr
Australia Forum Administrator #11
Please capture another packet or three of the prompt line. Maybe it changes in a way that skips the test. We could try to make it more general.

I've tested with your sample packet and it adds the newline.
#12
A couple of moves and prompts.


Incoming packet: 42 (278 bytes) at Monday, July 27, 2015, 9:57:58 PM

You eat a pipewe   59 6f 75 20 65 61 74 20 61 20 70 69 70 65 77 65
ed bread...You a   65 64 20 62 72 65 61 64 2e 0a 0d 59 6f 75 20 61
re no longer hun   72 65 20 6e 6f 20 6c 6f 6e 67 65 72 20 68 75 6e
gry......[01m<.[   67 72 79 2e 0a 0d 0a 0d 1b 5b 30 31 6d 3c 1b 5b
00m.[1m.[31m733.   30 30 6d 1b 5b 31 6d 1b 5b 33 31 6d 37 33 33 1b
[00m.[31mhp.[00m   5b 30 30 6d 1b 5b 33 31 6d 68 70 1b 5b 30 30 6d
(.[31m733.[00m)    28 1b 5b 33 31 6d 37 33 33 1b 5b 30 30 6d 29 20
.[1m.[34m406.[00   1b 5b 31 6d 1b 5b 33 34 6d 34 30 36 1b 5b 30 30
m.[34mma.[00m(.[   6d 1b 5b 33 34 6d 6d 61 1b 5b 30 30 6d 28 1b 5b
34m522.[00m) .[1   33 34 6d 35 32 32 1b 5b 30 30 6d 29 20 1b 5b 31
m.[32m569.[00m.[   6d 1b 5b 33 32 6d 35 36 39 1b 5b 30 30 6d 1b 5b
32mmv.[00m(.[36m   33 32 6d 6d 76 1b 5b 30 30 6d 28 1b 5b 33 36 6d
28388.[00m) s: .   32 38 33 38 38 1b 5b 30 30 6d 29 20 73 3a 20 1b
[1m.[01mok.[00m    5b 31 6d 1b 5b 30 31 6d 6f 6b 1b 5b 30 30 6d 20
.[1m.[35m127903.   1b 5b 31 6d 1b 5b 33 35 6d 31 32 37 39 30 33 1b
[00m.[35mgp.[00m   5b 30 30 6d 1b 5b 33 35 6d 67 70 1b 5b 30 30 6d
 .[1m.[01m>.[00m   20 1b 5b 31 6d 1b 5b 30 31 6d 3e 1b 5b 30 30 6d
 .[00m             20 1b 5b 30 30 6d


e..                65 0d 0a

Incoming packet: 44 (485 bytes) at Monday, July 27, 2015, 9:58:29 PM

.[36mGuild Hall.   1b 5b 33 36 6d 47 75 69 6c 64 20 48 61 6c 6c 1b
[00m.[00m...[1m.   5b 30 30 6d 1b 5b 30 30 6d 0a 0d 1b 5b 31 6d 1b
[31m[.[00m.[31mE   5b 33 31 6d 5b 1b 5b 30 30 6d 1b 5b 33 31 6d 45
xits:.[00m .[1z<   78 69 74 73 3a 1b 5b 30 30 6d 20 1b 5b 31 7a 3c
send>.[7z.[31mno   73 65 6e 64 3e 1b 5b 37 7a 1b 5b 33 31 6d 6e 6f
rth.[00m.[1z</se   72 74 68 1b 5b 30 30 6d 1b 5b 31 7a 3c 2f 73 65
nd>.[7z .[1z<sen   6e 64 3e 1b 5b 37 7a 20 1b 5b 31 7a 3c 73 65 6e
d>.[7z.[31meast.   64 3e 1b 5b 37 7a 1b 5b 33 31 6d 65 61 73 74 1b
[00m.[1z</send>.   5b 30 30 6d 1b 5b 31 7a 3c 2f 73 65 6e 64 3e 1b
[7z .[1z<send>.[   5b 37 7a 20 1b 5b 31 7a 3c 73 65 6e 64 3e 1b 5b
7z.[31msouth.[00   37 7a 1b 5b 33 31 6d 73 6f 75 74 68 1b 5b 30 30
m.[1z</send>.[7z   6d 1b 5b 31 7a 3c 2f 73 65 6e 64 3e 1b 5b 37 7a
 .[1z<send>.[7z.   20 1b 5b 31 7a 3c 73 65 6e 64 3e 1b 5b 37 7a 1b
[31mwest.[00m.[1   5b 33 31 6d 77 65 73 74 1b 5b 30 30 6d 1b 5b 31
z</send>.[7z.[31   7a 3c 2f 73 65 6e 64 3e 1b 5b 37 7a 1b 5b 33 31
m.[1m].[00m...[0   6d 1b 5b 31 6d 5d 1b 5b 30 30 6d 0a 0d 1b 5b 30
0m.....[01m<.[00   30 6d 0a 0d 0a 0d 1b 5b 30 31 6d 3c 1b 5b 30 30
m.[1m.[31m733.[0   6d 1b 5b 31 6d 1b 5b 33 31 6d 37 33 33 1b 5b 30
0m.[31mhp.[00m(.   30 6d 1b 5b 33 31 6d 68 70 1b 5b 30 30 6d 28 1b
[31m733.[00m) .[   5b 33 31 6d 37 33 33 1b 5b 30 30 6d 29 20 1b 5b
1m.[34m427.[00m.   31 6d 1b 5b 33 34 6d 34 32 37 1b 5b 30 30 6d 1b
[34mma.[00m(.[34   5b 33 34 6d 6d 61 1b 5b 30 30 6d 28 1b 5b 33 34
m522.[00m) .[1m.   6d 35 32 32 1b 5b 30 30 6d 29 20 1b 5b 31 6d 1b
[32m567.[00m.[32   5b 33 32 6d 35 36 37 1b 5b 30 30 6d 1b 5b 33 32
mmv.[00m(.[36m28   6d 6d 76 1b 5b 30 30 6d 28 1b 5b 33 36 6d 32 38
388.[00m) s: .[1   33 38 38 1b 5b 30 30 6d 29 20 73 3a 20 1b 5b 31
m.[31mstn.[00m .   6d 1b 5b 33 31 6d 73 74 6e 1b 5b 30 30 6d 20 1b
[1m.[35m127903.[   5b 31 6d 1b 5b 33 35 6d 31 32 37 39 30 33 1b 5b
00m.[35mgp.[00m    30 30 6d 1b 5b 33 35 6d 67 70 1b 5b 30 30 6d 20
.[1m.[01m>.[00m    1b 5b 31 6d 1b 5b 30 31 6d 3e 1b 5b 30 30 6d 20
.[00m              1b 5b 30 30 6d

Sent  packet: 46 (3 bytes) at Monday, July 27, 2015, 9:58:30 PM

w..                77 0d 0a

Incoming packet: 45 (356 bytes) at Monday, July 27, 2015, 9:58:30 PM

.[36mRoom of Rec   1b 5b 33 36 6d 52 6f 6f 6d 20 6f 66 20 52 65 63
ords.[00m.[00m..   6f 72 64 73 1b 5b 30 30 6d 1b 5b 30 30 6d 0a 0d
.[1m.[31m[.[00m.   1b 5b 31 6d 1b 5b 33 31 6d 5b 1b 5b 30 30 6d 1b
[31mExits:.[00m    5b 33 31 6d 45 78 69 74 73 3a 1b 5b 30 30 6d 20
.[1z<send>.[7z.[   1b 5b 31 7a 3c 73 65 6e 64 3e 1b 5b 37 7a 1b 5b
31meast.[00m.[1z   33 31 6d 65 61 73 74 1b 5b 30 30 6d 1b 5b 31 7a
</send>.[7z.[31m   3c 2f 73 65 6e 64 3e 1b 5b 37 7a 1b 5b 33 31 6d
.[1m].[00m...[00   1b 5b 31 6d 5d 1b 5b 30 30 6d 0a 0d 1b 5b 30 30
m.....[01m<.[00m   6d 0a 0d 0a 0d 1b 5b 30 31 6d 3c 1b 5b 30 30 6d
.[1m.[31m733.[00   1b 5b 31 6d 1b 5b 33 31 6d 37 33 33 1b 5b 30 30
m.[31mhp.[00m(.[   6d 1b 5b 33 31 6d 68 70 1b 5b 30 30 6d 28 1b 5b
31m733.[00m) .[1   33 31 6d 37 33 33 1b 5b 30 30 6d 29 20 1b 5b 31
m.[34m427.[00m.[   6d 1b 5b 33 34 6d 34 32 37 1b 5b 30 30 6d 1b 5b
34mma.[00m(.[34m   33 34 6d 6d 61 1b 5b 30 30 6d 28 1b 5b 33 34 6d
522.[00m) .[1m.[   35 32 32 1b 5b 30 30 6d 29 20 1b 5b 31 6d 1b 5b
32m565.[00m.[32m   33 32 6d 35 36 35 1b 5b 30 30 6d 1b 5b 33 32 6d
mv.[00m(.[36m283   6d 76 1b 5b 30 30 6d 28 1b 5b 33 36 6d 32 38 33
88.[00m) s: .[1m   38 38 1b 5b 30 30 6d 29 20 73 3a 20 1b 5b 31 6d
.[31mstn.[00m .[   1b 5b 33 31 6d 73 74 6e 1b 5b 30 30 6d 20 1b 5b
1m.[35m127903.[0   31 6d 1b 5b 33 35 6d 31 32 37 39 30 33 1b 5b 30
0m.[35mgp.[00m .   30 6d 1b 5b 33 35 6d 67 70 1b 5b 30 30 6d 20 1b
[1m.[01m>.[00m .   5b 31 6d 1b 5b 30 31 6d 3e 1b 5b 30 30 6d 20 1b
[00m               5b 30 30 6d

Australia Forum Administrator #13
I was afraid of that. Some of those packets don't have the prompt at the start. This somewhat more complex plugin scans the entire packet for the prompt, and also looks for multiple ones in one packet:

Template:saveplugin=Add_NewLine_To_Prompt_LPEG_re
To save and install the Add_NewLine_To_Prompt_LPEG_re plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Add_NewLine_To_Prompt_LPEG_re.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Add_NewLine_To_Prompt_LPEG_re.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.



<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE muclient>

<muclient>
<plugin
   name="Add_NewLine_To_Prompt_LPEG_re"
   author="Nick Gammon"
   id="af8df9687a2f1b01abb7d750"
   language="Lua"
   purpose="Forces a newline after a prompt line"
   date_written="2015-07-26"
   requires="4.67"
   version="1.1"
   >
</plugin>

<script>
<![CDATA[

require "re"

prompt = re.compile([[
  prompt <- crlf colour '<'                   -- start of prompt
            colour %d+ colour 'hp' colour     -- 733hp
            numberInBrackets                  -- (733)
            colour %d+ colour 'ma' colour     -- 522ma
            numberInBrackets                  -- (522)
            colour %d+ colour 'mv' colour     -- 569mv
            numberInBrackets                  -- (569)
            's:' %s+ colour %a+ colour        -- s: ok
            %d+ colour 'gp'                   -- 126636gp
            colour '>' colour                 -- closing > symbol

   numberInBrackets <- '(' colour %d+ colour ')' %s+

]] .. 

   -- escape codes like \027 \n \r do not work inside long strings

   "colour  <- ('\027' '[' %d+ 'm' %s*)* " ..  -- colour code: ESC [ 42 m
   "crlf    <- ('\n' / '\r')+"                 -- carriage return/line feed(s)
   )

-- make a non-anchored match and return the start and end position of the match
local I = lpeg.Cp()
function anywhere (p)
  return lpeg.P{ I * p * I + 1 * lpeg.V(1) }
end
       
function OnPluginPacketReceived (s)
  local result = ""
  
  -- find first prompt match
  first, last = lpeg.match (anywhere (prompt), s)
  -- if found, look for more prompts in the packet
  while last do
    -- add this one to the resulting string
    result = result .. s:sub (1, last - 1) .. "\n"
    s = s:sub (last)  -- string now smaller
    first, last = lpeg.match (anywhere (prompt), s) -- start again
    if not last then
      return result .. s
    end -- if
  end -- if

  -- no match, return packet  
  return s
end -- function OnPluginPacketReceived
]]>
</script>

</muclient>
Australia Forum Administrator #14
For the sake of my own sanity, I'm going to work through this:


local I = lpeg.Cp()
function anywhere (p)
  return lpeg.P{ I * p * I + 1 * lpeg.V(1) }
end


That code came from the official LPEG documentation.

The first line is straightforward enough:


local I = lpeg.Cp()


That makes a variable "I" which is lpeg.Cp() which returns the current capture position.

Now:


 lpeg.P{ I * p * I + 1 * lpeg.V(1) }


That creates a table (note the brackets style) which contains this:

  • Remember the current position (I) without consuming any characters
  • Try to match the pattern "p" (the prompt in this case)
  • Also remember the final position (the second I) without consuming any characters


If this succeeds then we have a match (in the first position of the target text) along with the first and last character position. This is returned to the caller.

Now since this is a table, this is really all in position 1 of the table. That is, it could have been written like this:


 lpeg.P{ [1] = I * p * I + 1 * lpeg.V(1) }


The number 1 is the key, and the rest of it is the value of key 1.

Now, consider what happens if we don't get a match in position 1. We now move on to the "or" part of the pattern:


+  1 * lpeg.V(1)


This won't happen if the pattern matches, because the "or" has a lower precedence than concatenation.

But if it doesn't, we now match on 1 (that is, consume 1 character unconditionally) and then execute variable 1 in the grammar. Well, variable 1 is element [1] in the array, so it basically recurses, and tries again in position 2.

Eventually we may get a match, maybe in position 50. When we do, we still know the first and last position of the match, which are returned. If not, it returns nil.
Amended on Tue 28 Jul 2015 06:44 AM by Nick Gammon
#15
And that seems to have done the trick.

Thank you very much Sir! This makes triggers SO much easier to work with now.

Some were showing up on their own line, others were showing up directly after the prompt. I couldn't figure out which were doing what.

CM