My Sloppy BookMaker bnds Parser -- Opinions Welcome!

This is part of a Newton Book Maker suite/project; Book Maker outputs NewtonScript style text files, with “bounds” based on a 240x320 screen. The Newton2100 can handle 1/3-again as much size, so time for bulk math! (I changed numbers by hand to test–it compiles and looks great, but, man!, is it tedious…)

(the “bnd” list is part of a larger file; the list looks like this:)

bnd12 := [0,40,240,52];
bnd13 := [0,52,240,64];
bnd14 := [0,64,240,318];

This droplet will take a text file made from a list as above. It pulls out the “bnd” sets, multiplies each element by 1.325, and saves the results in a new text file alogside the old one

This is a quick hack to save me a lot of typing. I humbly present the code here for any opinions! My version has a couple decent ideas, but it’s sloppy and slow and not very smart (ie., the data has to be in a pretty specific format). Come on! Rip it to shreds…! Seriously, I welcome any tips to streamline my little kludge.


on open theFile
	
	set RevisedBoundsFile to (extract_parent_folder_path_from(theFile)) & "Revised Bounds List.txt"
	set BoundsFile to (read theFile) as text
	
	repeat with i in paragraphs of BoundsFile
		set BoundsNumber to text ((offset of "d" in i) + 1) thru ((offset of ":" in i) - 2) of i
		set BoundsList to stringToList((text ((offset of "[" in i) + 1) thru ((offset of "]" in i) - 1) of i), ",")
		set RevisedList to {}
		set RevisedList to DoTheMath(BoundsList)
		set RevisedBoundsList to "bnd" & BoundsNumber & " := [" & RevisedList & "];" & return
		WriteToFile(RevisedBoundsList, RevisedBoundsFile, true)
	end repeat
end open

--snip from a macscripter.net post
on stringToList(theString, stringDelimiter)
	tell AppleScript
		set oldDelimiter to text item delimiters
		set text item delimiters to stringDelimiter
		set outList to text items of theString
		set text item delimiters to oldDelimiter
		return outList
	end tell
end stringToList

--sloppy snip from a macscripter.net post. could be more elegant; that if/else is nasty..
on DoTheMath(theList)
	set TempRevisedList to {}
	set listItemsNumber to number of items in theList
	repeat with ii from 1 to listItemsNumber
		if ii < listItemsNumber then
			set TempRevisedList to (TempRevisedList & (round of ((item ii of theList) * 1.325) rounding up) & ",")
		else
			set TempRevisedList to (TempRevisedList & (round of ((item ii of theList) * 1.325) rounding up))
		end if
	end repeat
end DoTheMath

--one of Sal Soghoian’s sample sun-routines...
to WriteToFile(this_data, target_file, append_data)
	try
		set the target_file to the target_file as text
		set the open_target_file to open for access file target_file with write permission
		if append_data is false then set eof of the open_target_file to 0
		write this_data to the open_target_file starting at eof
		close access the open_target_file
		return true
	on error
		try
			close access file target_file
		end try
		return false
	end try
end WriteToFile

--one of Sal Soghoian’s sample sun-routines...
on extract_parent_folder_path_from(this_filepath)
	set this_filepath to this_filepath as text
	set x to the offset of ":" in (the reverse of every character of this_filepath) as string
	set the parent_folder_path to (characters 1 thru -(x) of this_filepath) as text
	return the parent_folder_path
end extract_parent_folder_path_from

Equivalent script using Python, FYI:

#!/usr/bin/python

from math import ceil
from re import compile
from os.path import dirname, join
from sys import argv, exit

# constants
_pattern = compile('(w+) *:= *[(d+),(d+),(d+),(d+)];') # used to match lines in data file; non-matching lines are ignored
_scalefactor = 1.325 # the amount to scale bounds by
_destfilename = 'Revised Bounds List.txt' # name of output file (could take output file as a command-line argument if preferred)

# check inputs
if len(argv) != 2:
    print 'Usage: python RecalcBounds.py <file>'
    exit()

# read source file
f = open(argv[1]) # note: full path required (this could be made smarter if needed)
s = f.read()
f.close()

# extract data, do math on it and reformat result
r = []
for line in _pattern.findall(s):
    newsize = [ceil(int(i) * _scalefactor) for i in line[1:]]
    r.append('%s := [%i,%i,%i,%i];' % tuple([line[0]] + newsize))
s = 'n'.join(r)

# write destination file
f = open(join(dirname(argv[1]), _destfilename), 'w')
f.write(s)
f.close()

Significantly simpler (one of the benefits of having an excellent standard library at your disposal) and faster too - partly because Python itself is faster, partly because the text parsing is done more efficiently. (Regular expressions are ideal for this kind of work: much quicker and simpler than all that tiresome TID-munging; e.g. the Satimage OSAX is good for working with non-Unicode text.) You can easily tweak the regular expression pattern to make it more forgiving of the line formatting if necessary.

Save the above script as RecalcBounds.py, and type ‘python RecalcBounds.py /your/source/file/path’ in Terminal to run it. Or use MacPython’s bundlebuilder to turn it into a drag-n-drop applet.

HTH

Thank you so much, hhas! I am going to play with that right now. (I have been fascinated by Python for a while, and you have provided me an excellent point from which to start! That’s why the macscripter BBS is awesome!) My ultimate goal will be to incorporate this “parser” as part of a larger file processor–something to read the entire Book Maker “book.f” project file, for example. Thanks again!