Getting happier ;-), but wondering if I'm thinking pythonically

Graham Nicholls graham at rockcons.co.uk
Tue May 20 16:10:29 EDT 2003


Hi, and thanks to everyone for their replies to my earlier thread.  
The "Obfuscated Python" competition was a joke, BTW.  I'm getting rsi from
replying to all the posts & email I've had, but I'm not complaining - I
appreciate it.

Anyway, heres something I'm writing - it will strip out the fonttable from
multiple rtf files, and eventually merge them, patchng up fornt references
later.  Its so you can join several rtf files without losing font info. 
The C version works, but is failing in some specific circumstances (I have
an _idea_ why).  I thought I'd learn Python and do some useful coding at
the same time, but a couple of questions : 

Firstly, is this in general, the right way?  This is my second attempt - the
first program worked but didn't use classes, or optik, and was more limited
in scope.  BTW is using external modules like optik a bad idea if you want
programs to be portable (doesn't matter for this program, but might)

second, I want to use split and a RE to split the fonttable at a pattern,
hence lines 99-109.  This seems cumbersome - I'd like to do something like:


for (fnum,fdesc) in re.split(fntid_s,self.buff):
        add_to_a dictionary

Anyway, thanks for looking - I hope I'm OK in posting this here?

Graham 

    1   #!/usr/bin/env python
    2   
    3   # G.Nicholls 
    4   # Mon May 19 22:07:51 BST 2003
    5   # Python script to build a common font table from a set of rtf files.
    6   
    7   import string,os,sys
    8   import re
    9   
   10   # Use optik to handle command line.
   11   from optik import OptionParser, OptionError
   12   
   13   # Exit returns:
   14   BAD_ARGS=1
   15   OPEN_FAIL=2
   16   CREAT_FAIL=3
   17   NOT_RTF=4
   18   FILE_ERR=5
   19   INTERNAL_ERR=100
   20   
   21   version = "0.2"
   22   
   23   class rtffile:
   24       def __init__(self,file_name):
   25           """Create an instance of an rtffile object; calls
get_fonttbl"""
   26           self.fname=file_name
   27           try:
   28               self.fhand=open(self.fname,"r")
   29           except:         # This seems to be deprecated - why?
   30               print ("An error occurred opening the file %s" %
self.fname)
   31               sys.exit(OPEN_FAIL)
   32   
   33           # Read the file & then close it
   34           self.buff=self.fhand.read()
   35           self.fhand.close()
   36           # Then may as well set up the "pointers" to the data (yes, I
know!)
   37           self.get_fonttbl()
   38           return
   39   
   40       def __del__(self):
   41           if options.debug:
   42               print ("DEBUG: Destroying %s" % self.fname)
   43   
   44       def get_fonttbl(self):
   45           """Get the font definition from the font table creates a
fonttable instance"""
   46           ftbl_id=r"\fonttbl"
   47           if options.debug:
   48               print ("DEBUG: Seeking to font table [%s]  in %s " %
(ftbl_id,self.fname))
   49           tbl_start=self.buff.find(ftbl_id)
   50           if tbl_start == -1:
   51               print ("File %s is  not a properly formed rtf file" %
self.fname)
   52               sys.exit(NOT_RTF)
   53           
   54           len=find_len(self.buff[tbl_start:])
   55   
   56           if options.debug:
   57               print ("DEBUG: Found a font table of length %d at %d " %
(len,tbl_start))
   58   
   59   
   60           # Make a new instance of fonttable. 
   61           self.font_table=fonttable(self.buff,tbl_start,len)
   62   
   63           if options.debug:
   64               print ("DEBUG: heres the font table:\n")
   65               print self.font_table
   66   
   67           # Hold the end position so when we start to look for font
references, we know where to start
   68           self.ftable_end=tbl_start+len
   69           
   70           self.font_table.write(options.opfhand)
   71   
   72           pass
   73           
   74   class  fonttable:
   75       def __init__(self,buff,start,len):
   76           """Creates a new instance of a font table"""
   77   
   78           if options.debug:
   79               print ("DEBUG: Creating a new font table of %d bytes" %
len)
   80   
   81           self.buff=buff[start-1:start+len]       # start -1 to capture
the leading brace
   82           self.start=start
   83           self.len=len
   84               
   85   
   86       def __del__(self):
   87           if options.debug:
   88               print ("DEBUG: Deleting font table")
   89   
   90       def __repr__(self):
   91           """Display the contents of a font table"""
   92           return (self.buff)
   93   
   94       def write(self,fhand):
   95           """Write a nicely formatted font table to file handle fhand"""
   96   
   97           fid_s=r'{\\f(\d+)'      # re to match font identifier
   98   
   99           fonts={}
  100           fnum=0
  101           i=0
  102           for fontid in re.split(fid_s,self.buff):
  103               if i % 2 == 1:
  104                   fnum=fontid
  105               else:
  106                   fonts[fnum] = fontid
  107               i+=1
  108           for fontid in fonts.keys():
  109               print ("\n%s : %s\n" % (fontid, fonts[fontid]))
  110   
  111           pass
  112   
  113   # End of class definitions
  114
#######################################################################################################################################
  115   
  116   def setup_args(arglist):
  117       """Parse the command line and create the options list"""
  118   
  119       global options              # saves passing it around
  120       usage="%%prog (-dv) -o[output_file]"
  121       try: 
  122           parser=OptionParser(usage=usage,version="%%prog %s" %version)
  123           parser.add_option("-o", "--outfile",dest="opfname",
help="Specifies output file", metavar="FILE")
  124           parser.add_option("-d", "--debug",dest="debug",    
help="Switches on debugging", action="store_true",default=0)
  125           parser.add_option("-v", "--verbose",dest="verbose",
help="SWitches on verbose mode", action="store_true",default=0)
  126           (options,args) = parser.parse_args(arglist)
  127       except OptionError:
  128           print ("Error in option handling - exiting")
  129           sys.exit(INTERNAL_ERR)
  130       
  131       try:
  132           options.opfhand=open(options.opfname,"w")
  133       except IOError, msg:
  134           print ("Couldn't open output file %s : %s" % (options.opfname,
msg))
  135           sys.exit(CREAT_FAIL)
  136   
  137       if len(args) < 1 or options.opfname == None:
  138           print parser.print_help()
  139           sys.exit(BAD_ARGS)
  140       return (args)
  141   
  142   
  143   def main():
  144       """build a font table from several rtf files"""
  145   
  146       global progname
  147       global version
  148       progname=os.path.basename(sys.argv[0])
  149       flist=setup_args(sys.argv[1:])
  150   
  151       if len(flist) < 1:
  152           print ("Need a filename!")
  153           sys.exit(BAD_ARGS)
  154   
  155       if options.verbose:
  156           print ("%s version %s" % (progname,version))
  157           
  158       
  159       rtflist={}
  160       for fname in flist:
  161           rtflist[fname]=rtffile(fname)
  162           pass
  163           
  164   def find_len(str):
  165       """Find the length of the string up to a closing delimiter - 
  166           eg the length of a font definition"""
  167   
  168       brace_ct=1          # We've skipped the opening brace
  169       len=0
  170   
  171       while brace_ct > 0:
  172           try: 
  173               c=str[len]
  174           except IndexError:
  175               print ("Premature eof in %s possibly not a true rtf file?"
% str)
  176               sys.exit(FILE_ERR)
  177   
  178           if c == '{' :
  179               brace_ct=brace_ct + 1
  180           if c == '}' :
  181               brace_ct=brace_ct - 1
  182   
  183           len+=1
  184       return (len)
  185   
  186   if __name__ == '__main__': # ie we're _not_ a module
  187       main()
  188   
-- 
Graham Nicholls
All round good guy.




More information about the Python-list mailing list