New Global Replace dialog in the Notepad

Posted by Nick Gammon on Mon 05 Dec 2005 10:14 PM — 4 posts, 17,153 views.

Australia Forum Administrator #0
Sometimes when editing scripts (or forum messages) I feel the need for a more powerful find-and-replace system than is offered by the standard Windows Edit Control find-and-replace (the one used by the MUSHclient notepad).

Examples are:

  1. Change:

    
      aaa [bbb] = 50
      ccc [ddd] = 100
      eee [fff] = 250
      ggg [ggg] = 300
    


    to

    
      aaa ["bbb"] = 50
      ccc ["ddd"] = 100
      eee ["fff"] = 250
      ggg ["ggg"] = 300
    

  2. Change:

    
      aaa = bbb
      ccc = ddd
      eee = fff
    


    to:

    
      bbb = aaa
      ddd = ccc
      fff = eee
    


    (In other words, reverse what is being assigned to what).


Now, to save reinventing the wheel (again) I thought it would be handy to have the functionality of the Lua string.gsub available for easy use in the Notepad.

Accordingly, verion 3.71 of MUSHclient offers an alternative to the standard find/replace dialog, the new Global Replace dialog.

The selected text (or all text in the window if none is selected) will be sent to the string.gsub function, with the specified "find" and "replacement" text being used for the function, like this:


new_selection = string.gsub (old_selection, find_text, replacement_text)


If there is an error raised by string.gsub (eg. bad regular expression) then no text is replaced.

See the documentation for string.gsub in Lua for the exact workings of this function. Also see the forum posting:

http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=6034

You can replace in "line by line" mode, or "entire block" mode. Line-by-line is useful if you want to do something like add spaces (or remove spaces) at the start of each line.




Examples of doing the changes mentioned above:


Find: %[(.+)%]
Replace: ["%1"]


This changes [aaa] to ["aaa"]


And:


Find: ( *)(.*) = (.*)
Replace: %1%3 = %2


This swaps the things in an assignment statement, so:


a = b


becomes:


b = a





Replacement function

For extra power, you can specify a replacement function (as you can for string.gsub in Lua) and really make complex replacements.

For example, here is how you could fix up HTML codes using the Global Replace:


Find: [<>&]
Replace: f
Each line: no
Escape: no
Call Function: yes
Script:

replacements = { 
   ["<"] = "&lt;",
   [">"] = "&gt;",
   ["&"] = "&amp;",
   }

function f (str)
  return replacements [str] or str
  end


The "find" box specifies the set of "[<>&]" - in other words the HTML characters we need to fix.

The replacement function, called "f" is named in the replacement box. It is called by string.gsub. It uses a table lookup to map "<" to "&lt;" and so on.

Another example of using a function:


Find: %u+%A
Replace: f
Line by Line: no

Call Function: yes
Script:

function f (s)
  return string.lower (s)
end 


This searches for words that are in all upper-case (by searching for %u which is upper case letters, followed by %A which is something that is not a letter). When found the function "f" is called that converts it to lower-case.
Amended on Mon 05 Dec 2005 10:16 PM by Nick Gammon
Australia Forum Administrator #1
More example:


Add spaces to the start of each line


Find: ^
Replace: (some spaces here)
Line by Line: yes



Add a comment to the end of each line


Find: $
Replace:  // my comment
Line by Line: yes



Remove all leading spaces at the start of each line


Find: ^( *)
Replace: (nothing)
Line by Line: yes



Replace multiple spaces by a single space


Find: ( +)
Replace: (one space)
Line by Line: no



Replace tab characters by a space


Find: \t
Replace: (one space)
Line by Line: no
Escape Sequences: yes


This last example has "Escape Sequences" checked. This tells MUSHclient to interpret \t as a tab character.


Wrap lines by converting newlines to a space


Find: \n
Replace: (one space)
Line by Line: no
Escape Sequences: yes


Amended on Mon 05 Dec 2005 10:36 PM by Nick Gammon
Australia Forum Administrator #2
You can also use it as a counter, to see how many of a certain type of thing exists in a selection. The technique here is to do the replace, note the replacement count, and then hit Ctrl+Z to undo the change.

Examples:


Count quoted strings


Find: %b""
Replace: (nothing)
Line by Line: no


Hit OK, note the count (on the status bar), then hit Ctrl+Z to put the quoted strings back. Or, more safely:


Find: (%b"")
Replace: %1
Line by Line: no


This second example simply replaces the found text with itself, so it is not a problem if you forget to undo the replacement.


Count words


Find: (%a+)
Replace: %1
Line by Line: no

Amended on Mon 05 Dec 2005 10:36 PM by Nick Gammon
Australia Forum Administrator #3
You can also use inbuilt functions directly, without having to write a "wrapper" script. For example, to convert everything to upper case:


Find: .*
Replace: string.upper
Call Function: yes


In this case, since all we need to do is call string.upper, we can use the function directly, rather than having to write a wrapper function like this:


function f (s)
  return string.upper (s)
end


Only some functions lend themselves to this use, but some useful ones might be:


string.upper
string.lower
string.hash
utils.base64decode
utils.base64encode