-- limodou [2004-09-13 01:21:13]

1. Python 源代码转成Html

现在有许多的Python源码转成Html的程序,这个是从Moin中修改而来的

1.1. 关于

现在有许多的Python源码转成Html的程序,就我所知就有Moin, Twisted, DiveIntoPython带了一个,可能还有别的,我没有再查过。

本来PyTextile是可以将Python转成Html的,但它用的是twisted.python.htmlizer,不过在程序它将导入位置改为了:

import htmlizer

结果要你将htmlizer从twisted中拷贝出来才可以,但现在的htmlizer还要调用别的模块。因些我放弃了。当然,改一下是行的,不过没这么做。

DiveIntoPython的作者Mark Pilgrim写的,也是要用到别的东西。因此还是放弃了。

最后选定了Moin中的python.py。不过,与老版本不同,它使用了wiki的一个应用模块,主要是进行特殊字符的html处理,我改成了cgi模块。但还是发现,对传入的文本是unicode时,处理有问题,没办法改吧。最后形成了这个版本,已经不再是原来的东西了。

1.2. 代码

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - Python Source Parser
   4 
   5     @copyright: 2001 by J黵gen Hermann <[email protected]>
   6     @license: GNU GPL, see COPYING for details.
   7 """
   8 
   9 # Imports
  10 import cStringIO
  11 import keyword, token, tokenize
  12 import cgi
  13 import types
  14 
  15 #############################################################################
  16 ### Python Source Parser (does Hilighting)
  17 #############################################################################
  18 
  19 _KEYWORD = token.NT_OFFSET + 1
  20 _TEXT    = token.NT_OFFSET + 2
  21 
  22 _colors = {
  23     token.NUMBER:       '#0080C0',
  24     token.OP:           '#0000C0',
  25     token.STRING:       '#804000',
  26     tokenize.COMMENT:   '#008000',
  27     token.NAME:         '#000000',
  28     token.ERRORTOKEN:   '#FF8080',
  29     _KEYWORD:           '#0000FF',
  30     _TEXT:              '#000000',
  31 }
  32 
  33 
  34 class Parser:
  35     """ Send colored python source.
  36     """
  37 
  38     def __init__(self, raw):
  39         """ Store the source text.
  40         """
  41         self.raw = raw.expandtabs().rstrip()
  42         self.unicode = False
  43         self.result = []
  44 
  45     def format(self, linenumber=True):
  46         """ Parse and send the colored source.
  47         """
  48         # store line offsets in self.lines
  49         if isinstance(self.raw, types.UnicodeType):
  50             self.raw = self.raw.encode('utf-8')
  51             self.unicode = True
  52 
  53         self.lines = [0, 0]
  54         pos = 0
  55         while 1:
  56             pos = self.raw.find('\n', pos) + 1
  57             if not pos: break
  58             self.lines.append(pos)
  59         self.lines.append(len(self.raw))
  60 
  61         # write line numbers
  62         if linenumber:
  63             self.result.append('<table border="0"><tr><td align="right" valign="top">')
  64             self.result.append('<td align="right" valign="top"><pre><font face="Lucida,Courier New" color="%s">' % _colors[_TEXT])
  65             for idx in range(1, len(self.lines)-1):
  66                 self.result.append('%3d \n' % idx)
  67             self.result.append('</font></pre></td><td valign="top">')
  68 
  69         # parse the source and write it
  70         self.pos = 0
  71         text = cStringIO.StringIO(self.raw)
  72         self.result.append('<pre><font face="Lucida,Courier New">')
  73         try:
  74             tokenize.tokenize(text.readline, self)
  75         except tokenize.TokenError, ex:
  76             msg = ex[0]
  77             line = ex[1][0]
  78             self.result.append("<h3>ERROR: %s</h3>%s\n" % (
  79                 msg, self.raw[self.lines[line]:]))
  80         self.result.append('</font></pre>')
  81 
  82         # close table
  83         if linenumber:
  84             self.result.append('</td></tr></table>')
  85 
  86         text = ''.join(self.result)
  87         if self.unicode:
  88             text = unicode(text, 'utf-8')
  89         return text
  90 
  91     def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
  92         """ Token handler.
  93         """
  94         if 0: print "type", toktype, token.tok_name[toktype], "text", toktext, \
                    "start", srow,scol, "end", erow,ecol, "<br>"
  95 
  96         # calculate new positions
  97         oldpos = self.pos
  98         newpos = self.lines[srow] + scol
  99         self.pos = newpos + len(toktext)
 100 
 101         # handle newlines
 102         if toktype in [token.NEWLINE, tokenize.NL]:
 103             self.result.append('\n')
 104             return
 105 
 106         # send the original whitespace, if needed
 107         if newpos > oldpos:
 108             self.result.append(self.raw[oldpos:newpos])
 109 
 110         # skip indenting tokens
 111         if toktype in [token.INDENT, token.DEDENT]:
 112             self.pos = newpos
 113             return
 114 
 115         # map token type to a color group
 116         if token.LPAR <= toktype and toktype <= token.OP:
 117             toktype = token.OP
 118         elif toktype == token.NAME and keyword.iskeyword(toktext):
 119             toktype = _KEYWORD
 120         color = _colors.get(toktype, _colors[_TEXT])
 121 
 122         style = ''
 123         if toktype == token.ERRORTOKEN:
 124             style = ' style="border: solid 1.5pt #FF0000;"'
 125 
 126         # send text
 127         self.result.append('<font color="%s"%s>' % (color, style))
 128         if toktype == _KEYWORD:
 129             self.result.append('<b>')
 130         self.result.append(cgi.escape(toktext))
 131         if toktype == _KEYWORD:
 132             self.result.append('</b>')
 133         self.result.append('</font>')
 134 
 135 if __name__ == "__main__":
 136     import os
 137     print "Formatting..."
 138 
 139     # open own source
 140     source = open('colourize.py').read()
 141 
 142     # write colorized version to "python.html"
 143     file('colourize.html', 'w').write(Parser(source).format(False))

format中的linenumber可以控制是否要生成行号。

1.3. 讨论