-- limodou [DateTime(2004-09-13T01:21:13Z)] TableOfContents

Python 源代码转成Html

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

关于

现在有许多的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 # -*- 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, \
  95                     "start", srow,scol, "end", erow,ecol, "<br>"
  96 
  97         # calculate new positions
  98         oldpos = self.pos
  99         newpos = self.lines[srow] + scol
 100         self.pos = newpos + len(toktext)
 101 
 102         # handle newlines
 103         if toktype in [token.NEWLINE, tokenize.NL]:
 104             self.result.append('\n')
 105             return
 106 
 107         # send the original whitespace, if needed
 108         if newpos > oldpos:
 109             self.result.append(self.raw[oldpos:newpos])
 110 
 111         # skip indenting tokens
 112         if toktype in [token.INDENT, token.DEDENT]:
 113             self.pos = newpos
 114             return
 115 
 116         # map token type to a color group
 117         if token.LPAR <= toktype and toktype <= token.OP:
 118             toktype = token.OP
 119         elif toktype == token.NAME and keyword.iskeyword(toktext):
 120             toktype = _KEYWORD
 121         color = _colors.get(toktype, _colors[_TEXT])
 122 
 123         style = ''
 124         if toktype == token.ERRORTOKEN:
 125             style = ' style="border: solid 1.5pt #FF0000;"'
 126 
 127         # send text
 128         self.result.append('<font color="%s"%s>' % (color, style))
 129         if toktype == _KEYWORD:
 130             self.result.append('<b>')
 131         self.result.append(cgi.escape(toktext))
 132         if toktype == _KEYWORD:
 133             self.result.append('</b>')
 134         self.result.append('</font>')
 135 
 136 if __name__ == "__main__":
 137     import os
 138     print "Formatting..."
 139 
 140     # open own source
 141     source = open('colourize.py').read()
 142 
 143     # write colorized version to "python.html"
 144     file('colourize.html', 'w').write(Parser(source).format(False))

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

讨论