Regular Expressions and Scripts – Worked Example

Programmer’s Notepad has great support for Regular Expressions baked in, supporting much more than the restricted syntax that many Scintilla-based editors provide. For example, did you know that you can use negative lookarounds to find text that doesn’t contain a pattern? This regular expression matches any line that doesn’t contain “not here”:

^((?!not here).)*$

Sometimes I find myself repeating the same set of Search/Replace operations in order to format text. If I’m going to do this more than a couple of times, I record a script using PyPN to make things easier for myself. Today I was turning text like this:

    LogStep("Do something");
    MyClass.DoReallyCleverStuff();
    MyClass.VerifySomethingAwesome();
    
    LogStep("Do another thing");
    MyClass.DoSomethingLessClever();
    MyClass.VerifySomethingBad();

Into text like this:


Do something
Do another thing

There are many ways to do something like this, and I could have written a PyPN script by hand to do it. However, combining Regular Expressions and Script Recording means I can do this without a lot of manual code effort. Here’s what I did:

  1. Tools > Record Script
  2. Replace All: ^((?!LogStep).)*$ with (nothing)
  3. Replace All: (\r\n){2,} with \r\n
  4. Replace All: \s*LogStep\("([^"]+)"\); with \1
  5. Tools > Stop Recording

At the end of this Programmer’s Notepad added a script to the Scripts window (Recorded\New Script) and placed the code for that script in a new editor window. Because I wanted to keep the script for future use, I changed it’s name and saved it to C:\Program Files\Programmer’s Notepad\Scripts. Here’s the script (which I reduced slightly for posting here):

import pn, scintilla

@script("Clean Up Log Steps", "Testing")
def CleanUpLogSteps():
	doc = pn.CurrentDoc()
	sci = scintilla.Scintilla(doc)
	opt = pn.GetUserSearchOptions()
	opt.FindText = u'^((?!LogStep).)*$'
	opt.MatchWholeWord = False
	opt.MatchCase = False
	opt.UseRegExp = True
	opt.SearchBackwards = False
	opt.LoopOK = True
	opt.UseSlashes = False
	opt.ReplaceText = u''
	opt.ReplaceInSelection = False
	doc.ReplaceAll(opt)
	# When recording, the result of this operation was: pn.FindNextResult(37)

	opt.FindText = u'(\\r\\n\\r\\n){2,}'
	opt.ReplaceText = u'\\r\\n'
	doc.ReplaceAll(opt)
	# When recording, the result of this operation was: pn.FindNextResult(16)

	opt.FindText = u'\\s*LogStep\\("([^"]+)"\\);'
	opt.ReplaceText = u'\\1'
	doc.ReplaceAll(opt)
	# When recording, the result of this operation was: pn.FindNextResult(10)

If I was going to use this script a lot, I could bind it to a shortcut key in Tools > Options > Keyboard.

2 comments

  1. Hat Tip to this StackOverflow question for the regular expression to match lines that don’t contain some text:

    http://stackoverflow.com/questions/406230/regular-expression-to-match-string-not-containing-a-word

  2. Neat! It’s fun to see what PN can do. I’ve been stuck using VS2010 for a while, and it really makes me miss PN.