Hyperlink a list of people

Posted by Gore on Wed 09 Aug 2006 04:56 AM — 18 posts, 71,475 views.

#0
Basically I've got a list of people

3540h, 4515m cexkdb-
Chidori, Isis, Aurielle, Zoya, Solarus, Mynte, Mourdred, Mazacheli, Sigao, 
Wynedere, Delphinus, Jibrille, Niar, Danya, Namino, Crythril, Skarash, Raymath.
3540h, 4515m cexkdb-


I want to take that list of people, and convert them to hyperlinks so that I can click them, and it does hnsb and the name.

this is what I have so far:


<aliases>
  <alias
   script="enable_theft_qw"
   match="^cqw$"
   enabled="y"
   regexp="y"
   ignore_case="y"
   keep_evaluating="y"
   sequence="100"
  >
  </alias>
</aliases>

<triggers>
  <trigger
   keep_evaluating="y"
   match="(| )(\w+)(\,|\.)"
   name="theft_qw"
   regexp="y"
   repeat="y"
   script="theft_qw_hyperlink"
   sequence="100"
  >
  </trigger>
</triggers>

sub Enable_Theft_PK (a,b,wildcard)
  world.enabletrigger "theft_qw", 0
  world.send "qw"
  world.doafterspecial .5, "world.enabletrigger ""theft_qw"", 0", 12
end sub

sub Theft_QW_Hyperlink (a,b,wildcard)
  world.Hyperlink "hnsb" & wildcard(2), wildcard(2), "click here to honours " & wildcard(1), "blue", "white", 0
end sub


but it spits out this:

3540h, 4515m cexkdb-
Chidori, Isis, Aurielle, Zoya, Solarus, Mynte, Mourdred, Mazacheli, Sigao, 
Chidori
Wynedere, Delphinus, Jibrille, Niar, Danya, Namino, Crythril, Skarash, Raymath.
Wynedere
3540h, 4515m cexkdb-
3540h


and what I really want is an exact replica of the formatting with the names on the same line, just as hyperlinks. Also any suggestions with the organization of subroutine naming and trigger grouping/naming?
Russia #1
You can use the following pattern:


^([A-Z][a-z]+)[,.]?((?:\s[A-Z][a-z]+[,.])*)([A-Z][a-z]+)?[,.]?\s?$


This will return 3 wildcards with names. If there's only one name on the line, e.g.:


3540h, 4515m cexkdb-
Chidori.
3540h, 4515m cexkdb-


then 2nd and 3rd wildcards will be empty. With only 2 names on the line the 2nd wildcard will be empty. With 3 or more names, all 3 wildcards will contain strings.

The first wildcard always holds the first name on the line, without a comma or period. Second holds all names between the first and the last, each name followed by a comma. The third wildcard has the last name, without any punctuation.

The script to handle this should go along the lines of (Lua):


function ShowNames(n,o,wildcs)
   local names = {}  -- an array of names
   table.insert(names,wildcs[1])  -- append the first name

   -- if 2nd wildcard is not empty
   if wildcs[2] then
      
      -- split it into a table around commas, removing the last element from the resulting array
     local scnd = utils.split(wildcs[2], ",")
     table.remove(scnd)
     -- now append the values from "scnd" to the names array
     for _,v in ipairs(scnd) do
        table.insert(names, scnd)
     end
   end

   -- if 3rd wildcard is not empty
   if wildcs[3] then
      -- add it to the names
      table.insert(names, wildcs[3])
   end

   -- Display the names
   for _,v in ipairs(names) do
      world.Hyperlink ("hnsb" .. v, v, "click here to honours " .. v, "blue", "white", 0)
   end
end


Though, on a second thought, you could probably just split the entire matched line.

Another thing is that you probably want to keep the trigger disabled when it is not needed, so it doesn't go matching names in all sorts of lists, unless that's what you want.
Amended on Wed 09 Aug 2006 06:04 AM by Ked
#2
Anyway to do this in vbscript? I really don't understand how tables work.. heh
Amended on Wed 09 Aug 2006 06:02 AM by Gore
Russia #3
Erm, I can't remember much of Vbscript myself. All I can help you with is how to split the second wildcard:


scnd = split(wildcs[1], ",")


That's all I can be more or less certain about, but neither my memory nor Vbscript's docs are any help in figuring out how to remove an element from an array or concatenate two arrays together.

You'll probably be better off just splitting the entire matched string, and then somehow removing the period from the last string in the resulting array. That'll be only two lines of code, the first being:


names = split(wildcs[10], ",")


and the second would involve a Replace(strText, ".", "").
#4
I guess I ment to ask for more of a written answer than a coded answer. I don't understand Lua at all so I don't know what you mean. Are you basically taking the entire string of "1, 2, 3, 4, 5." taking them out, putting them into their own entities minus the ,'s and ., then for to next looping them into a hyperlink?
#5
Ohhhhhhhhhh, ok. I didn't realize if you hyperlinked twice in a sub routine they will be put on the same line hehe. I should be fine from now.. I hope
#6
Should I stay away from do until loops whenever possible?
Russia #7
In this particular case the only use for such a loop would be to output items in an array, consuming them along the way. There's no point to that since a "for each" loop will do the job just fine without any extra operations.
#8
Is there anyway to output a non hyperlinked comma or period when I have a bunch of hyperlinks?

for instance

Blah(hyperlinked),(not) Blah2(hyperlinked).(not)
#9
sorry, just found out that colournote will make the note right beside it.. thanks anyway
USA #10
I did something like this in a plugin of mine where it spit out a bunch of item names and each one was blue and had a different hyperlink, while inbetween was a bunch of yellow commas...

Here's an example of what you can do.

Use Ked's regexp to capture
^([A-Z][a-z]+)[,.]?((?:\s[A-Z][a-z]+[,.])*)([A-Z][a-z]+)?[,.]?\s?$

Dim, a, playernames
'wildcards(1) will be the first name in the list.
'Either add a few more ifs to work around it, or just add it to the end.  (I added it to the end in this script.)
PlayerNames = split(wildcards(2),", ")

'Do some clean up
playernames(0) = trim(playernames(0))
'This removes the period or comma on the end of the last name.
playernames(ubound(playernames)) = left(playernames(ubound(playernames)),len(playernames(ubound(playernames)) - 1)

redim preserve playernames(ubound(playernames)) 'add one more onto array and toss the wildcards(1) name onto the end.
playernames(ubound(playernames)) = wildcards(1)

Dim PrintedLength 
'The point in this little routine is if 
'you don't wrap it yourself MUSH tries to wrap it and you 
'end up with half of a hyperlink that doesn't work, so 
'this should wrap it before MUSH tries to.

for a = 0 to ubound(playername)
PrintedLength = PrintedLength & playernames(a) & ", "

If len(PrintedLength) > 79 Then 'Since you can't find what the client wraps at, just wrap at 80.
 world.note " "
 world.Hyperlink "Write your sweet hyperlink here." PrintedLength = playernames(a) & ", "
else
 world.Hyperlink "Write your sweet hyperlink here."
end if

If a = ubound(playernames) then
else
  world.Colourtell "yellow", "black", ", " 'Here's your comma, insert it after each name, but not if we're on the last name.
'Colourtell must be used, since it doesn't terminate with a newline.
end if
next

Note: This is just a basic example that can be improved a lot, like by setting a = playernames(ubound(playernames)) so the program doesn't ahve to keep finding the array's ubound.
Amended on Fri 18 Aug 2006 06:07 AM by NeoFryBoy
Australia Forum Administrator #11
Quote:

Since you can't find what the client wraps at, just wrap at 80.


You can:


Note (GetOption ("wrap_column")) --> 80
#12
Ok, sorry for the delay everyone. but no one else's scripts had been working for me. I decided to learn Lua, and finally get this thing to work for me. I tried Ked's script, but received a ton of errors, along with my friend who also uses Lua. The main issue was getting around the fact that the beginning characters could be ", " or the first name, and the last characters would be either the last name or "," or ", " or "." So getting around all of these conditions was a pain.. heh

so, if anyone could tell me how to clean this up, I would appreciate it.

For the mud, Aetolia:
H:1500 M:1374 [eb]
Acino, Adamant, Aelia, Althalus, Amelas, Amiya, Ansnom, Ansury, Arbre, Aren, 
Arinwen, Arivan, Armin, Arorn, Aspoehro, Aviv, Bain, Beren, Borscin, Butoken, 
Charlius, Choderic, Chthon, Daelin, Dagan, Desian, Draqon, Ecikoria, Elinja, 
Elorin, Emikalia, Entildron, Eretria, Erzsebet, Estelyx, Evilo, Ezrax, Feichin, 
Garoul, Gawdin, Gex, Graythe, Halisstra, Ianus, Imiroari, Indalecio, Istoria, 
Jeisha, Jherrek, Jorachim, Karim, Kidasu, Kuroken, Lynette, Macian, Makano, 
Maximas, Merelii, Mikal, Minois, Morana, Nahual, Nelien, Neoma, Nero, Nicholas, 
Numax, Nymeria, Osifer, Plato, Posh, Qix, Ranac, Rasta, Rastaban, Reach, 
Requilem, Reuel, Rhelora, Roselynn, Ryath, Ryban, Rynthia, Sagla, Saigusa, 
Savanna, Scottswarbrick, Serafena, Sesoh, Sethiel, Sylfaen, Tetchta, Theris, 
Tremaday, Truft, Tsatra, Turc, Vaneas, Victoria, Virillya, Visk, Xandradi, Xanrl
, Ynael, Yura, Yurameki, Zanzarious, Zaurtha, Zerath, Zizor, Zoharim, and 
Zossima.
H:1500 M:1374 [eb]

becomes:

H:1500 M:1374 [eb]
Acino, Adamant, Aelia, Althalus, Amelas, Amiya, Ansnom, Ansury, Arbre, Aren,
Arinwen, Arivan, Armin, Arorn, Aspoehro, Aviv, Bain, Beren, Borscin, Butoken,
Charlius, Choderic, Chthon, Daelin, Dagan, Desian, Draqon, Ecikoria, Elinja,
Elorin, Emikalia, Entildron, Eretria, Erzsebet, Estelyx, Evilo, Ezrax, Feichin,
Garoul, Gawdin, Gex, Graythe, Halisstra, Ianus, Imiroari, Indalecio, Istoria,
Jeisha, Jherrek, Jorachim, Karim, Kidasu, Kuroken, Laedien, Lynette, Macian,
Makano, Maximas, Merelii, Mikal, Minois, Morana, Nahual, Nelien, Neoma, Nero,
Nicholas, Numax, Nymeria, Osifer, Plato, Posh, Qix, Ranac, Rasta, Rastaban,
Reach, Requilem, Reuel, Rhelora, Roselynn, Ryath, Ryban, Rynthia, Sagla, Saigusa,
Savanna, Scottswarbrick, Serafena, Sesoh, Sethiel, Sylfaen, Tetchta, Theris,
Tremaday, Truft, Tsatra, Turc, Vaneas, Victoria, Virillya, Visk, Xandradi, Xanrl,
Ynael, Yura, Yurameki, Zanzarious, Zaurtha, Zerath, Zizor, Zoharim,
Zossima.
H:1500 M:1374 [eb]

<aliases>
  <alias
   script="enable_shownames"
   match="^cqw$"
   enabled="y"
   group="auto-theft"
   regexp="y"
   ignore_case="y"
   keep_evaluating="y"
   sequence="100"
  >
  </alias>
</aliases>

<triggers>
  <trigger
   group="auto-theft"
   match="^H\:(\d+) M\:(\d+) [(.*?)]$"
   name="theft_prompt"
   regexp="y"
   script="disable_shownames"
   sequence="1"
  >
  </trigger>
  <trigger
   group="auto-theft"
   keep_evaluating="y"
   match="^(.*?)$"
   name="theft_qw"
   omit_from_log="y"
   omit_from_output="y"
   regexp="y"
   repeat="y"
   script="test_shownames"
   sequence="100"
  >
  </trigger>
</triggers>

function enable_shownames (n,o,wc)
  EnableTrigger ("theft_qw", true)
  EnableTrigger ("theft_prompt", true)
  Send ("qw")
end

function disable_shownames (n,o,wc)
  EnableTrigger ("theft_qw", false)
  EnableTrigger ("theft_prompt", false)
end

function test_shownames (n,o,wc)
  local qw_line = wc[1]
  if string.sub (qw_line, string.len(qw_line)) ~= "," and string.sub (qw_line, string.len(qw_line)) ~= " " then
    qw_line = qw_line .. ","
  end
  if string.sub (qw_line, 1, 2) == ", " then
    qw_line = string.gsub (qw_line, ", ", "", 1)
  end
  qw_line = string.gsub (qw_line, "and ", "")
  local names = utils.split(qw_line, ",")
  table.remove (names)
  for key, value in ipairs(names) do
    value = string.gsub(value, " ", "")
    if key == table.maxn (names) then
      if string.sub (value, string.len(value)) == "." then
        value = string.sub (value, 1, string.len(value)-1)
        Hyperlink ("honours " .. value , value, "click here to honours " .. value, "blue", "white", 0) 
        ColourNote ("dimgray", "white", ".")
        return
      end
    end
    Hyperlink ("honours " .. value , value, "click here to honours " .. value, "blue", "white", 0)
    if key == table.maxn (names) then
      ColourNote ("dimgray", "white", ",")
      return
    end
    ColourTell ("dimgray", "white", ", ")
  end
end


can you tell me what you think? And how can I make this code neater/look nicer?
Amended on Mon 29 Jan 2007 08:03 PM by Gore
Australia Forum Administrator #13
I think you can simplify it a bit. This is my example code:


wholist = [[
Acino, Adamant, Aelia, Althalus, Amelas, Amiya, Ansnom, Ansury, Arbre, Aren, 
Arinwen, Arivan, Armin, Arorn, Aspoehro, Aviv, Bain, Beren, Borscin, Butoken, 
Charlius, Choderic, Chthon, Daelin, Dagan, Desian, Draqon, Ecikoria, Elinja, 
Elorin, Emikalia, Entildron, Eretria, Erzsebet, Estelyx, Evilo, Ezrax, Feichin, 
Garoul, Gawdin, Gex, Graythe, Halisstra, Ianus, Imiroari, Indalecio, Istoria, 
Jeisha, Jherrek, Jorachim, Karim, Kidasu, Kuroken, Lynette, Macian, Makano, 
Maximas, Merelii, Mikal, Minois, Morana, Nahual, Nelien, Neoma, Nero, Nicholas, 
Numax, Nymeria, Osifer, Plato, Posh, Qix, Ranac, Rasta, Rastaban, Reach, 
Requilem, Reuel, Rhelora, Roselynn, Ryath, Ryban, Rynthia, Sagla, Saigusa, 
Savanna, Scottswarbrick, Serafena, Sesoh, Sethiel, Sylfaen, Tetchta, Theris, 
Tremaday, Truft, Tsatra, Turc, Vaneas, Victoria, Virillya, Visk, Xandradi, Xanrl
, Ynael, Yura, Yurameki, Zanzarious, Zaurtha, Zerath, Zizor, Zoharim, and 
Zossima.
]]

wholist = string.gsub (wholist, "\n", " ")  -- wrap lines
wholist = string.gsub (wholist, "  ", " ")  -- 2 spaces become 1
wholist = string.gsub (wholist, " ,", ",")  -- space-comma becomes comma
wholist = string.gsub (wholist, "and (.-)%.", "%1,") -- final "and blah." becomes "blah,"

for w in string.gmatch (wholist , " *(.-),") do
  print (w)
end -- for


As you can see from the comments, I try to normalize the who list by merging lines (converting newlines to a space), or if they are separate lines you would concatenate them.

Then I convert 2 spaces to 1 space. Then any space-comma sequences becomes a single comma.

Finally the final "and whoever." becomes simply "whoever," to be consistent with the other names.

Finally a string.gmatch picks out each name. This is the result:


Acino
Adamant
Aelia
Althalus
Amelas
Amiya
Ansnom
Ansury
Arbre
Aren
Arinwen
Arivan
... and so on ...
Zoharim
Zossima



[EDIT]

Amended slightly because the first name wasn't showing up. Now the test for leading spaces is for "zero or more", and the first name now appears.
Amended on Tue 30 Jan 2007 06:42 AM by Nick Gammon
#14
Quote:
As you can see from the comments, I try to normalize the who list by merging lines (converting newlines to a space), or if they are separate lines you would concatenate them.


How did you do that exactly?

Edit: More specifically, how did you get all of the lines into one string? Something along the lines of:

Trigger: ^(.*?)$
Send to script: wholist_string = wholist_string .. %1

?
Amended on Wed 31 Jan 2007 06:53 PM by Gore
Australia Forum Administrator #15
In my test above, I simply used a multi-line string, which would have had \n (newline) characters at the end of each line.

If you are building it up, line-by-line, I would use:

Send to script: wholist_string = wholist_string .. " " .. "%1"

First, you need to quote %1, otherwise you will get all sorts of strange errors. Second, I would put in a space, so that a word at the end of one line doesn't run into a word at the start of the next, although that may not be necessary depending on the exact data.
#16
Is it considered poor practice that I don't actually use any sort of scripting in my aliases/triggers/timers, but rather I always reference a function/subroutine?

And thanks a lot for your help! I think I might have to do it your way, as I plan to expand this script.
Amended on Thu 01 Feb 2007 12:58 AM by Gore
Australia Forum Administrator #17
I don't have a problem with using the script file for bigger projects - for one thing, you get syntax checking at the start (when the script is loaded), and not when each alias etc. is used.

I tend to use "send to script" for simple actions, and also for demonstrating things here in the forum, because I don't have to tell people to copy and paste code into a script file, set the file name in the scripting tab, and so on.